Shield Security for WordPress - Version 3.5.5

Version Description

  • ADDED: Better admin notifications for events such as options saving etc.
  • CHANGE: Some plugin styling to highlight features and options better.
  • FIXED: Small bug with options default values.
Download this release

Release Info

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

Code changes from version 3.0.0 to 3.5.5

Files changed (91) hide show
  1. icwp-plugin-controller.php +479 -0
  2. icwp-wpsf-main.php +343 -396
  3. icwp-wpsf.php +34 -87
  4. languages/wp-simple-firewall-es_ES.mo +0 -0
  5. languages/wp-simple-firewall-fr_FR.mo +0 -0
  6. languages/wp-simple-firewall-pt_BR.mo +0 -0
  7. mode.login_throttled +0 -0
  8. readme.txt +79 -5
  9. resources/css/global-plugin.css +33 -0
  10. resources/css/plugin.css +37 -1
  11. resources/js/bootstrap.min.js +6 -0
  12. src/config/feature-admin_access_restriction.txt +48 -0
  13. src/config/feature-audit_trail.txt +75 -0
  14. src/config/feature-autoupdates.txt +108 -0
  15. src/config/feature-comments_filter.txt +172 -0
  16. src/config/feature-email.txt +34 -0
  17. src/config/feature-firewall.txt +155 -0
  18. src/config/feature-lockdown.txt +66 -0
  19. src/config/feature-logging.txt +27 -0
  20. src/config/feature-login_protect.txt +182 -0
  21. src/config/feature-plugin.txt +94 -0
  22. src/config/feature-user_management.txt +102 -0
  23. src/icwp-base-processor.php +0 -384
  24. src/icwp-data-processor.php +481 -408
  25. src/icwp-foundation.php +44 -0
  26. src/icwp-import-base-processor.php +0 -84
  27. src/icwp-import-wpf2-processor.php +0 -147
  28. src/icwp-options-vo.php +373 -0
  29. src/icwp-optionshandler-admin_access_restriction.php +134 -92
  30. src/icwp-optionshandler-audit_trail.php +150 -0
  31. src/icwp-optionshandler-autoupdates.php +146 -176
  32. src/icwp-optionshandler-base.php +750 -849
  33. src/icwp-optionshandler-comments_filter.php +318 -214
  34. src/icwp-optionshandler-email.php +53 -35
  35. src/icwp-optionshandler-firewall.php +177 -222
  36. src/icwp-optionshandler-lockdown.php +88 -110
  37. src/icwp-optionshandler-logging.php +51 -27
  38. src/icwp-optionshandler-login_protect.php +212 -218
  39. src/icwp-optionshandler-plugin.php +119 -69
  40. src/icwp-optionshandler-privacy_protect.php +9 -15
  41. src/icwp-optionshandler-user_management.php +140 -58
  42. src/{icwp-processor-adminaccessrestriction.php → icwp-processor-admin_access_restriction.php} +9 -4
  43. src/icwp-processor-audit_trail.php +225 -0
  44. src/icwp-processor-audit_trail_plugins.php +93 -0
  45. src/icwp-processor-audit_trail_posts.php +136 -0
  46. src/icwp-processor-audit_trail_themes.php +74 -0
  47. src/icwp-processor-audit_trail_users.php +160 -0
  48. src/icwp-processor-audit_trail_wordpress.php +84 -0
  49. src/icwp-processor-autoupdates.php +25 -21
  50. src/icwp-processor-base.php +333 -0
  51. src/{icwp-basedb-processor.php → icwp-processor-basedb.php} +126 -51
  52. src/icwp-processor-comments_filter.php +100 -0
  53. src/{icwp-processor-commentsfilter.php → icwp-processor-commentsfilter_antibotspam.php} +61 -258
  54. src/icwp-processor-commentsfilter_humanspam.php +309 -0
  55. src/icwp-processor-email.php +5 -5
  56. src/icwp-processor-firewall.php +8 -26
  57. src/icwp-processor-lockdown.php +108 -104
  58. src/icwp-processor-logging.php +11 -12
  59. src/icwp-processor-login_protect.php +225 -0
  60. src/icwp-processor-loginprotect.php +0 -1030
  61. src/icwp-processor-loginprotect_cooldown.php +111 -0
  62. src/icwp-processor-loginprotect_gasp.php +169 -0
  63. src/icwp-processor-loginprotect_twofactorauth.php +548 -0
  64. src/icwp-processor-loginprotect_yubikey.php +167 -0
  65. src/icwp-processor-plugin.php +205 -11
  66. src/icwp-processor-privacyprotect.php +9 -17
  67. src/{icwp-processor-usermanagement.php → icwp-processor-user_management.php} +221 -66
  68. src/icwp-processor-usermanagement_adminloginnotification.php +79 -0
  69. src/icwp-processor-yaml.php +65 -0
  70. src/icwp-pure-base.php +303 -876
  71. src/icwp-wpfilesystem.php +290 -242
  72. src/icwp-wpfunctions.php +494 -199
  73. src/lib/yaml/Spyc.php +1147 -0
  74. views/icwp-wpsf-access_restricted_index.php +20 -21
  75. views/icwp-wpsf-audit_trail_viewer_index.php +126 -0
  76. views/icwp-wpsf-changlog_summary.php +118 -0
  77. views/icwp-wpsf-config-options-table.php +1 -1
  78. views/icwp-wpsf-config_autoupdates_index.php +2 -2
  79. views/icwp-wpsf-config_header.php +9 -9
  80. views/icwp-wpsf-config_plugin_index.php +4 -247
  81. views/icwp-wpsf-config_summary.php +128 -0
  82. views/icwp-wpsf-config_user_management_index.php +3 -1
  83. views/{icwp_wpsf_firewall_log_index.php → icwp-wpsf-firewall_log_index.php} +1 -1
  84. views/{icwp_wpsf_privacy_protect_log_index.php → icwp-wpsf-privacy_protect_log_index.php} +1 -1
  85. views/icwp_options_helper.php +59 -51
  86. views/icwp_wpsf_index.php +1 -1
  87. views/include_js.php +1 -1
  88. views/snippets/admin_notice_mailchimp.php +18 -0
  89. views/snippets/admin_notice_override.php +4 -0
  90. views/snippets/admin_notice_plugin_upgraded.php +6 -0
  91. views/snippets/admin_notice_translate_plugin.php +11 -0
icwp-plugin-controller.php ADDED
@@ -0,0 +1,479 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * "WordPress Simple Firewall" is distributed under the GNU General Public License, Version 2,
7
+ * June 1991. Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin
8
+ * St, Fifth Floor, Boston, MA 02110, USA
9
+ *
10
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
11
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
12
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
13
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
14
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
15
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
16
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
17
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20
+ */
21
+
22
+ require_once(dirname(__FILE__).ICWP_DS.'src'.ICWP_DS.'icwp-foundation.php');
23
+ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
24
+
25
+ /**
26
+ * @var ICWP_WPSF_Spec
27
+ */
28
+ private static $oPluginSpec;
29
+
30
+ /**
31
+ * @const string
32
+ */
33
+ const ViewDir = 'views';
34
+
35
+ /**
36
+ * @const string
37
+ */
38
+ const SrcDir = 'src';
39
+
40
+ /**
41
+ * @var string
42
+ */
43
+ protected static $fLoggingEnabled;
44
+
45
+ /**
46
+ * @var string
47
+ */
48
+ private $sPluginUrl;
49
+
50
+ /**
51
+ * @var string
52
+ */
53
+ private $sPluginBaseFile;
54
+
55
+ /**
56
+ * @var ICWP_WPSF_Plugin_Controller
57
+ */
58
+ public static $oInstance;
59
+
60
+ /**
61
+ * @param ICWP_WPSF_Spec $oPluginSpec
62
+ * @return ICWP_WPSF_Plugin_Controller
63
+ */
64
+ public static function GetInstance( $oPluginSpec ) {
65
+ if ( !isset( self::$oInstance ) ) {
66
+ self::$oInstance = new self( $oPluginSpec );
67
+ }
68
+ return self::$oInstance;
69
+ }
70
+
71
+ /**
72
+ * @param ICWP_WPSF_Spec $oPluginSpec
73
+ */
74
+ private function __construct( $oPluginSpec ) {
75
+ if ( empty( self::$oPluginSpec ) ) {
76
+ self::$oPluginSpec = $oPluginSpec;
77
+ add_action( 'plugins_loaded', array( $this, 'onWpPluginsLoaded' ) );
78
+ add_action( 'shutdown', array( $this, 'onWpShutdown' ) );
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Hooked to 'plugins_loaded'
84
+ */
85
+ public function onWpPluginsLoaded() {
86
+ if ( $this->getIsValidAdminArea() ) {
87
+ add_action( 'admin_notices', array( $this, 'onWpAdminNotices' ) );
88
+ add_action( 'network_admin_notices', array( $this, 'onWpAdminNotices' ) );
89
+ add_filter( 'all_plugins', array( $this, 'filter_hidePluginFromTableList' ) );
90
+ add_filter( 'site_transient_update_plugins', array( $this, 'filter_hidePluginUpdatesFromUI' ) );
91
+ add_action( 'in_plugin_update_message-'.$this->getPluginBaseFile(), array( $this, 'onWpPluginUpdateMessage' ) );
92
+ }
93
+ $this->doPluginFormSubmit();
94
+ $this->doLoadTextDomain();
95
+ }
96
+
97
+ /**
98
+ */
99
+ public function onWpAdminNotices() {
100
+ // Do we have admin priviledges?
101
+ if ( !$this->getIsValidAdminArea() ) {
102
+ return true;
103
+ }
104
+ $aAdminNotices = apply_filters( $this->doPluginPrefix( 'admin_notices' ), array() );
105
+ if ( empty( $aAdminNotices ) || !is_array( $aAdminNotices ) ) {
106
+ return;
107
+ }
108
+ foreach( $aAdminNotices as $sAdminNotice ) {
109
+ echo $sAdminNotice;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Displays a message in the plugins listing when a plugin has an update available.
115
+ */
116
+ public function onWpPluginUpdateMessage() {
117
+ $sMessage = apply_filters( $this->doPluginPrefix( 'plugin_update_message' ), '' );
118
+ if ( empty( $sMessage ) ) {
119
+ $sMessage = '';
120
+ }
121
+ else {
122
+ $sMessage = sprintf(
123
+ '<div class="%s plugin_update_message">%s</div>',
124
+ $this->getPluginPrefix(),
125
+ $sMessage
126
+ );
127
+ }
128
+ echo $sMessage;
129
+ }
130
+
131
+ /**
132
+ * Hooked to 'shutdown'
133
+ */
134
+ public function onWpShutdown() {
135
+ do_action( $this->doPluginPrefix( 'plugin_shutdown' ) );
136
+ }
137
+
138
+ /**
139
+ * Added to a WordPress filter ('all_plugins') which will remove this particular plugin from the
140
+ * list of all plugins based on the "plugin file" name.
141
+ *
142
+ * @param array $aPlugins
143
+ * @return array
144
+ */
145
+ public function filter_hidePluginFromTableList( $aPlugins ) {
146
+
147
+ $fHide = apply_filters( $this->doPluginPrefix( 'hide_plugin' ), false );
148
+
149
+ if ( !$fHide ) {
150
+ return $aPlugins;
151
+ }
152
+
153
+ $sPluginBaseFileName = $this->getPluginBaseFile();
154
+ if ( isset( $aPlugins[$sPluginBaseFileName] ) ) {
155
+ unset( $aPlugins[$sPluginBaseFileName] );
156
+ }
157
+ return $aPlugins;
158
+ }
159
+
160
+ /**
161
+ * Added to the WordPress filter ('site_transient_update_plugins') in order to remove visibility of updates
162
+ * from the WordPress Admin UI.
163
+ *
164
+ * In order to ensure that WordPress still checks for plugin updates it will not remove this plugin from
165
+ * the list of plugins if DOING_CRON is set to true.
166
+ *
167
+ * @uses $this->fHeadless if the plugin is headless, it is hidden
168
+ * @param StdClass $oPlugins
169
+ * @return StdClass
170
+ */
171
+ public function filter_hidePluginUpdatesFromUI( $oPlugins ) {
172
+
173
+ if ( $this->loadWpFunctionsProcessor()->getIsCron() ) {
174
+ return $oPlugins;
175
+ }
176
+
177
+ if ( ! apply_filters( $this->doPluginPrefix( 'hide_plugin_updates' ), false ) ) {
178
+ return $oPlugins;
179
+ }
180
+
181
+ if ( isset( $oPlugins->response[ $this->getPluginBaseFile() ] ) ) {
182
+ unset( $oPlugins->response[ $this->getPluginBaseFile() ] );
183
+ }
184
+ return $oPlugins;
185
+ }
186
+
187
+ /**
188
+ * @return string
189
+ */
190
+ public function getAdminMenuTitle() {
191
+ return self::$oPluginSpec->getAdminMenuTitle();;
192
+ }
193
+
194
+ /**
195
+ * @return string
196
+ */
197
+ public function getBasePermissions() {
198
+ return self::$oPluginSpec->getBasePermissions();
199
+ }
200
+
201
+ /**
202
+ * @param bool $fCheckUserPermissions
203
+ * @return bool
204
+ */
205
+ public function getIsValidAdminArea( $fCheckUserPermissions = true ) {
206
+ if ( $fCheckUserPermissions && !current_user_can( $this->getBasePermissions() ) ) {
207
+ return false;
208
+ }
209
+
210
+ $oWp = $this->loadWpFunctionsProcessor();
211
+ if ( !$oWp->isMultisite() && is_admin() ) {
212
+ return true;
213
+ }
214
+ else if ( $oWp->isMultisite() && $this->getIsWpmsNetworkAdminOnly() && is_network_admin() ) {
215
+ return true;
216
+ }
217
+ return false;
218
+ }
219
+
220
+ /**
221
+ */
222
+ protected function doLoadTextDomain() {
223
+ return load_plugin_textdomain(
224
+ $this->getTextDomain(),
225
+ false,
226
+ plugin_basename( $this->getPath_Languages() )
227
+ );
228
+ }
229
+
230
+ protected function doPluginFormSubmit() {
231
+ if ( !$this->getIsPluginFormSubmit() ) {
232
+ return false;
233
+ }
234
+
235
+ // do all the plugin feature/options saving
236
+ do_action( $this->doPluginPrefix( 'form_submit' ) );
237
+
238
+ if ( $this->getIsPage_PluginAdmin() ) {
239
+ $oWp = $this->loadWpFunctionsProcessor();
240
+ $oWp->doRedirect( $oWp->getUrl_CurrentAdminPage() );
241
+ return true;
242
+ }
243
+ }
244
+
245
+ /**
246
+ * @param string $sSuffix
247
+ * @param string $sGlue
248
+ * @return string
249
+ */
250
+ public function doPluginPrefix( $sSuffix = '', $sGlue = '-' ) {
251
+ $sPrefix = $this->getPluginPrefix( $sGlue );
252
+
253
+ if ( $sSuffix == $sPrefix || strpos( $sSuffix, $sPrefix.$sGlue ) === 0 ) { //it already has the full prefix
254
+ return $sSuffix;
255
+ }
256
+
257
+ return sprintf( '%s%s%s', $sPrefix, empty($sSuffix)? '' : $sGlue, empty($sSuffix)? '' : $sSuffix );
258
+ }
259
+
260
+ /**
261
+ * @param string $sSuffix
262
+ * @return string
263
+ */
264
+ public function doPluginOptionPrefix( $sSuffix = '' ) {
265
+ return $this->doPluginPrefix( $sSuffix, '_' );
266
+ }
267
+
268
+ /**
269
+ * @param string
270
+ * @return string
271
+ */
272
+ public function getOptionStoragePrefix() {
273
+ return $this->getPluginPrefix( '_' ).'_';
274
+ }
275
+
276
+ /**
277
+ * @param string
278
+ * @return string
279
+ */
280
+ public function getPluginPrefix( $sGlue = '-' ) {
281
+ return sprintf( '%s%s%s', $this->getParentSlug(), $sGlue, $this->getPluginSlug() );
282
+ }
283
+
284
+ /**
285
+ * @return string
286
+ */
287
+ public function getHumanName() {
288
+ return self::$oPluginSpec->getHumanName();
289
+ }
290
+
291
+ /**
292
+ * @return string
293
+ */
294
+ public function getIsLoggingEnabled() {
295
+ return self::$oPluginSpec->getIsLoggingEnabled();
296
+ }
297
+
298
+ /**
299
+ * @return bool
300
+ */
301
+ protected function getIsPage_PluginAdmin() {
302
+ $oWp = $this->loadWpFunctionsProcessor();
303
+ return ( strpos( $oWp->getCurrentWpAdminPage(), $this->getPluginPrefix() ) === 0 );
304
+ }
305
+
306
+ /**
307
+ * @return bool
308
+ */
309
+ protected function getIsPluginFormSubmit() {
310
+ if ( empty( $_POST ) && empty( $_GET ) ) {
311
+ return false;
312
+ }
313
+
314
+ $aFormSubmitOptions = array(
315
+ $this->doPluginOptionPrefix( 'plugin_form_submit' ),
316
+ 'icwp_link_action'
317
+ );
318
+
319
+ $oDp = $this->loadDataProcessor();
320
+ foreach( $aFormSubmitOptions as $sOption ) {
321
+ if ( !is_null( $oDp->FetchRequest( $sOption ) ) ) {
322
+ return true;
323
+ }
324
+ }
325
+ return false;
326
+ }
327
+
328
+ /**
329
+ * @return string
330
+ */
331
+ public function getIsWpmsNetworkAdminOnly() {
332
+ return self::$oPluginSpec->getIsWpmsNetworkAdminOnly();
333
+ }
334
+
335
+ /**
336
+ * @return string
337
+ */
338
+ public function getParentSlug() {
339
+ return self::$oPluginSpec->getParentSlug();
340
+ }
341
+
342
+ /**
343
+ * This is the path to the main plugin file relative to the WordPress plugins directory.
344
+ *
345
+ * @return string
346
+ */
347
+ public function getPluginBaseFile() {
348
+ if ( !isset( $this->sPluginBaseFile ) ) {
349
+ $this->sPluginBaseFile = plugin_basename( $this->getRootFile() );
350
+ }
351
+ return $this->sPluginBaseFile;
352
+ }
353
+
354
+ /**
355
+ * @return string
356
+ */
357
+ public function getPluginSlug() {
358
+ return self::$oPluginSpec->getPluginSlug();
359
+ }
360
+
361
+ /**
362
+ * @param string $sPath
363
+ * @return string
364
+ */
365
+ public function getPluginUrl( $sPath = '' ) {
366
+ if ( empty( $this->sPluginUrl ) ) {
367
+ $this->sPluginUrl = plugins_url( '/', $this->getRootFile() );
368
+ }
369
+ return $this->sPluginUrl.$sPath;
370
+ }
371
+
372
+ /**
373
+ * @param string $sCss
374
+ * @return string
375
+ */
376
+ public function getPluginUrl_Css( $sCss ) {
377
+ return $this->getPluginUrl( 'resources/css/'.$sCss );
378
+ }
379
+
380
+ /**
381
+ * @param string $sImage
382
+ * @return string
383
+ */
384
+ public function getPluginUrl_Image( $sImage ) {
385
+ return $this->getPluginUrl( 'resources/images/'.$sImage );
386
+ }
387
+
388
+ /**
389
+ * @param string $sJs
390
+ * @return string
391
+ */
392
+ public function getPluginUrl_Js( $sJs ) {
393
+ return $this->getPluginUrl( 'resources/js/'.$sJs );
394
+ }
395
+
396
+ /**
397
+ * @param string $sFeature
398
+ * @return string
399
+ */
400
+ public function getPluginUrl_AdminPage( $sFeature = '' ) {
401
+ return network_admin_url( sprintf( 'admin.php?page=%s', $this->doPluginPrefix( $sFeature ) ) );
402
+ }
403
+
404
+ /**
405
+ * get the root directory for the plugin with the trailing slash
406
+ *
407
+ * @return string
408
+ */
409
+ public function getPath_Languages() {
410
+ return $this->getRootDir().'languages'.ICWP_DS;
411
+ }
412
+
413
+ /**
414
+ * get the root directory for the plugin with the trailing slash
415
+ *
416
+ * @return string
417
+ */
418
+ public function getRootDir() {
419
+ return dirname( $this->getRootFile() ).ICWP_DS;
420
+ }
421
+
422
+ /**
423
+ * @return string
424
+ */
425
+ public function getRootFile() {
426
+ return self::$oPluginSpec->getRootFile();
427
+ }
428
+
429
+ /**
430
+ * Get the directory for the plugin source files with the trailing slash
431
+ *
432
+ * @param string $sSourceFile
433
+ * @return string
434
+ */
435
+ public function getSourceDir( $sSourceFile = '' ) {
436
+ return $this->getRootDir().self::SrcDir.ICWP_DS.$sSourceFile;
437
+ }
438
+
439
+ /**
440
+ * @return string
441
+ */
442
+ public function getTextDomain() {
443
+ return self::$oPluginSpec->getTextDomain();
444
+ }
445
+
446
+ /**
447
+ * @return string
448
+ */
449
+ public function getVersion() {
450
+ return self::$oPluginSpec->getVersion();
451
+ }
452
+
453
+ /**
454
+ * get the directory for the plugin view with the trailing slash
455
+ *
456
+ * @return string
457
+ */
458
+ public function getViewDir() {
459
+ return $this->getRootDir().self::ViewDir.ICWP_DS;
460
+ }
461
+
462
+ /**
463
+ * Retrieve the full path to the plugin view
464
+ *
465
+ * @param string $sView
466
+ * @return string
467
+ */
468
+ public function getViewPath( $sView ) {
469
+ return $this->getViewDir().$sView.'.php';
470
+ }
471
+
472
+ /**
473
+ * @param string $sSnippet
474
+ * @return string
475
+ */
476
+ public function getViewSnippet( $sSnippet ) {
477
+ return $this->getViewDir().'snippets'.ICWP_DS.$sSnippet.'.php';
478
+ }
479
+ }
icwp-wpsf-main.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  /**
4
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
5
  * All rights reserved.
@@ -21,459 +20,407 @@
21
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
  */
23
 
24
- require_once( dirname(__FILE__).'/src/icwp-pure-base.php' );
25
- require_once( dirname(__FILE__).'/src/icwp-data-processor.php' );
26
-
27
- if ( !function_exists( '_wpsf_e' ) ) {
28
- function _wpsf_e( $insStr ) {
29
- _e( $insStr, 'wp-simple-firewall' );
30
- }
31
- }
32
- if ( !function_exists( '_wpsf__' ) ) {
33
- function _wpsf__( $insStr ) {
34
- return __( $insStr, 'wp-simple-firewall' );
35
- }
36
- }
37
 
38
  if ( !class_exists('ICWP_Wordpress_Simple_Firewall') ):
39
 
40
- class ICWP_Wordpress_Simple_Firewall extends ICWP_Pure_Base_V5 {
41
-
42
- /**
43
- * @var string
44
- */
45
- const AdminAccessKeyCookieName = 'icwp_wpsf_aakcook';
46
-
47
- /**
48
- * @var ICWP_WPSF_FeatureHandler_Plugin
49
- */
50
- protected $oPluginOptions;
51
- /**
52
- * @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction
53
- */
54
- protected $oAdminAccessRestrictionOptions;
55
- /**
56
- * @var ICWP_WPSF_FeatureHandler_Firewall
57
- */
58
- protected $oFirewallOptions;
59
- /**
60
- * @var ICWP_WPSF_FeatureHandler_LoginProtect
61
- */
62
- protected $oLoginProtectOptions;
63
-
64
- /**
65
- * @var ICWP_WPSF_FeatureHandler_PrivacyProtect
66
- */
67
- protected $oPrivacyProtectOptions;
68
-
69
- /**
70
- * @var ICWP_WPSF_FeatureHandler_CommentsFilter
71
- */
72
- protected $oCommentsFilterOptions;
73
-
74
- /**
75
- * @var ICWP_WPSF_FeatureHandler_Lockdown
76
- */
77
- protected $oLockdownOptions;
78
-
79
- /**
80
- * @var ICWP_WPSF_FeatureHandler_Autoupdates
81
- */
82
- protected $oAutoupdatesOptions;
83
-
84
- /**
85
- * @var ICWP_WPSF_FeatureHandler_Email
86
- */
87
- protected $oEmailOptions;
88
-
89
- /**
90
- * @var ICWP_WPSF_FeatureHandler_Logging
91
- */
92
- protected $oLoggingOptions;
93
-
94
- /**
95
- */
96
- public function __construct( ICWP_Wordpress_Simple_Firewall_Plugin $oPluginVo ) {
97
- parent::__construct( $oPluginVo );
98
-
99
- $this->loadAllFeatures();
100
- add_filter( $this->doPluginPrefix( 'has_permission_to_view' ), array( $this, 'hasPermissionToView' ) );
101
- add_filter( $this->doPluginPrefix( 'has_permission_to_submit' ), array( $this, 'hasPermissionToSubmit' ) );
102
- }
103
-
104
- public function onWpActivatePlugin() {
105
- $this->loadAllFeatures( true, true );
106
- }
107
-
108
- /**
109
- * @param bool $fRecreate
110
- * @param bool $fFullBuild
111
- * @return bool
112
- */
113
- protected function loadAllFeatures( $fRecreate = false, $fFullBuild = false ) {
114
- foreach( $this->oPluginVo->getFeatures() as $sFeature ) {
115
- $fSuccess = $this->loadFeatureHandler( $sFeature, $fRecreate, $fFullBuild );
116
  }
117
- return $fSuccess;
118
- }
119
 
120
- protected function loadFeatureHandler( $sFeatureSlug = 'plugin', $infRecreate = false, $infFullBuild = false ) {
121
- if ( !$this->getIsFeature( $sFeatureSlug ) ) {
122
- return false;
123
  }
124
 
125
- $sFeatureName = str_replace( ' ', '', ucwords( str_replace( '_', ' ', $sFeatureSlug ) ) );
126
- $sOptionsVarName = 'o'.$sFeatureName.'Options'; // e.g. oPluginOptions
127
-
128
- if ( isset( $this->{$sOptionsVarName} ) ) {
129
- return $this->{$sOptionsVarName};
 
 
 
130
  }
131
- $sSourceFile = $this->oPluginVo->getSourceDir().'icwp-optionshandler-'.$sFeatureSlug.'.php'; // e.g. icwp-optionshandler-plugin.php
132
- $sClassName = 'ICWP_WPSF_FeatureHandler_'.$sFeatureName; // e.g. ICWP_WPSF_FeatureHandler_Plugin
133
 
134
- require_once( $sSourceFile );
135
- if ( $infRecreate || !isset( $this->{$sOptionsVarName} ) ) {
136
- $this->{$sOptionsVarName} = new $sClassName( $this->oPluginVo );
137
- }
138
- if ( $infFullBuild ) {
139
- $this->{$sOptionsVarName}->buildOptions();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  }
141
- return $this->{$sOptionsVarName};
142
- }
143
 
144
- /**
145
- * Given a certain feature 'slug' will return true if this is a particular supported feature of this plugin.
146
- *
147
- * @param string $sFeature
148
- * @return boolean
149
- */
150
- public function getIsFeature( $sFeature ) {
151
- return in_array( $sFeature, $this->oPluginVo->getFeatures() );
152
- }
153
 
154
- /**
155
- * @param array $aItems
156
- * @return array $aItems
157
- */
158
- public function filter_addExtraAdminMenuItems( $aItems ) {
159
- $aItems[ _wpsf__('Firewall Log' ) ] = array( 'Firewall Log', $this->getSubmenuId('firewall_log'), array( $this, 'onDisplayAll' ) );
160
- return $aItems;
161
- }
162
 
163
- /**
164
- * Displaying all views now goes through this central function and we work out
165
- * what to display based on the name of current hook/filter being processed.
166
- */
167
- public function onDisplayAll() {
168
 
169
- if ( !$this->hasPermissionToView() ) {
170
- $this->onDisplayAccessKeyRequest();
171
- return;
172
- }
173
 
174
- // Just to ensure the nag bar disappears if/when they visit the dashboard
175
- // regardless of clicking the button.
176
- $this->updateVersionUserMeta();
177
-
178
- $sPrefix = str_replace(' ', '-', strtolower( $this->oPluginVo->getAdminMenuTitle() ) ) .'_page_'.$this->getPluginPrefix().'-';
179
- $sCurrent = str_replace( $sPrefix, '', current_filter() );
180
-
181
- switch( $sCurrent ) {
182
- case 'privacy_protect_log' :
183
- $this->onDisplayPrivacyProtectLog();
184
- break;
185
- case 'firewall_log' :
186
- $this->onDisplayFirewallLog();
187
- break;
188
- default:
189
- $this->getFeatureHandler_MainPlugin()->displayFeatureConfigPage();
190
- break;
191
  }
192
- }
193
-
194
- /**
195
- * @param string $sSubmenu
196
- * @return array
197
- */
198
- protected function getBaseDisplayData( $sSubmenu = '' ) {
199
- $aBaseData = parent::getBaseDisplayData( $sSubmenu );
200
- $aBaseData['aMainOptions'] = $this->oPluginOptions->getPluginOptionsValues();
201
- return $aBaseData;
202
- }
203
 
204
- protected function onDisplayPrivacyProtectLog() {
 
 
 
 
 
 
 
 
205
 
206
- $oPrivacyProcessor = $this->getProcessor_PrivacyProtect();
207
- $aData = array(
208
- 'urlrequests_log' => $oPrivacyProcessor->getLogs( true )
209
- );
210
- $aData = array_merge( $this->getBaseDisplayData('privacy_protect_log'), $aData );
211
- $this->display( $this->doPluginPrefix( 'privacy_protect_log_index', '_' ), $aData );
212
- }
213
 
214
- protected function onDisplayFirewallLog() {
 
 
 
215
 
216
- $this->loadFeatureHandler( 'firewall' );
217
- $aIpWhitelist = $this->oFirewallOptions->getOpt( 'ips_whitelist' );
218
- $aIpBlacklist = $this->oFirewallOptions->getOpt( 'ips_blacklist' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
 
220
- $oLoggingProcessor = $this->getProcessor_Logging();
221
- $aLogData = $oLoggingProcessor->getLogs( true );
222
 
223
- $aData = array(
224
- 'firewall_log' => $aLogData,
225
- 'ip_whitelist' => isset( $aIpWhitelist['ips'] )? $aIpWhitelist['ips'] : array(),
226
- 'ip_blacklist' => isset( $aIpBlacklist['ips'] )? $aIpBlacklist['ips'] : array(),
227
- );
228
- $aData = array_merge( $this->getBaseDisplayData('firewall_log'), $aData );
229
- $this->display( $this->doPluginPrefix( 'firewall_log_index', '_' ), $aData );
230
- }
231
 
232
- public function onWpAdminInit() {
233
- parent::onWpAdminInit();
234
 
235
- if ( $this->isValidAdminArea() ) {
236
- //Someone clicked the button to acknowledge the update
237
- $sMetaFlag = $this->doPluginPrefix( 'hide_update_notice' );
238
- if ( $this->fetchRequest( $sMetaFlag ) == 1 ) {
239
- $this->updateVersionUserMeta();
240
- if ( $this->isShowMarketing() ) {
241
- wp_redirect( $this->getUrl_PluginDashboard() );
242
- }
243
- else {
244
- wp_redirect( network_admin_url( $_POST['redirect_page'] ) );
245
- }
246
  }
247
 
248
- $sMetaFlag = $this->doPluginPrefix( 'hide_translation_notice' );
249
- if ( $this->fetchRequest( $sMetaFlag ) == 1 ) {
250
- $this->updateTranslationNoticeShownUserMeta();
251
- wp_redirect( network_admin_url( $_POST['redirect_page'] ) );
252
  }
253
 
254
- $sMetaFlag = $this->doPluginPrefix( 'hide_mailing_list_signup' );
255
- if ( $this->fetchRequest( $sMetaFlag ) == 1 ) {
256
- $this->updateMailingListSignupShownUserMeta();
257
- }
 
 
 
 
258
  }
259
- }
260
 
261
- /**
262
- * @return bool
263
- */
264
- protected function isShowMarketing() {
265
- return apply_filters( $this->doPluginPrefix( 'show_marketing' ), true );
266
- }
267
 
268
- protected function getPluginsListUpdateMessage() {
269
- return _wpsf__( 'Upgrade Now To Keep Your Firewall Up-To-Date With The Latest Features.' );
270
- }
271
 
272
- protected function getAdminNoticeHtml_Translations() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
 
274
- if ( $this->getInstallationDays() < 7 ) {
275
- return '';
 
 
 
 
 
 
 
 
276
  }
277
 
278
- $sMetaFlag = $this->doPluginPrefix( 'hide_translation_notice' );
279
-
280
- $sRedirectPage = 'index.php';
281
- ob_start(); ?>
282
- <style>
283
- a#fromIcwp { padding: 0 5px; border-bottom: 1px dashed rgba(0,0,0,0.1); color: blue; font-weight: bold; }
284
- </style>
285
- <form id="IcwpTranslationsNotice" method="post" action="admin.php?page=<?php echo $this->getSubmenuId('firewall'); ?>&<?php echo $sMetaFlag; ?>=1">
286
- <input type="hidden" value="<?php echo $sRedirectPage; ?>" name="redirect_page" id="redirect_page">
287
- <input type="hidden" value="1" name="<?php echo $sMetaFlag; ?>" id="<?php echo $sMetaFlag; ?>">
288
- <h4 style="margin:10px 0 3px;">
289
- <?php _wpsf_e( 'Would you like to help translate the WordPress Simple Firewall into your language?' ); ?>
290
- <?php printf( _wpsf__( 'Head over to: %s' ), '<a href="http://translate.icontrolwp.com" target="_blank">translate.icontrolwp.com</a>' ); ?>
291
- </h4>
292
- <input type="submit" value="<?php _wpsf_e( 'Dismiss this notice' ); ?>" name="submit" class="button" style="float:left; margin-bottom:10px;">
293
- <div style="clear:both;"></div>
294
- </form>
295
- <?php
296
- $sNotice = ob_get_contents();
297
- ob_end_clean();
298
- return $sNotice;
299
- }
300
 
301
- protected function getAdminNoticeHtml_VersionUpgrade() {
 
 
302
 
303
- // for now just showing this for the first 3 days of installation.
304
- if ( $this->getInstallationDays() > 7 ) {
305
- return '';
306
- }
 
 
 
307
 
308
- $sMetaFlag = $this->doPluginPrefix( 'hide_update_notice' );
309
-
310
- $sRedirectPage = 'admin.php?page=icwp-wpsf';
311
- ob_start(); ?>
312
- <style>a#fromIcwp { padding: 0 5px; border-bottom: 1px dashed rgba(0,0,0,0.1); color: blue; font-weight: bold; }</style>
313
- <form id="IcwpUpdateNotice" method="post" action="admin.php?page=<?php echo $this->getSubmenuId('firewall'); ?>&<?php echo $sMetaFlag; ?>=1">
314
- <input type="hidden" value="<?php echo $sRedirectPage; ?>" name="redirect_page" id="redirect_page">
315
- <input type="hidden" value="1" name="<?php echo $sMetaFlag; ?>" id="<?php echo $sMetaFlag; ?>">
316
- <p>
317
- <?php _wpsf_e( 'Note: WordPress Simple Firewall plugin does not automatically turn on when you install/update.' ); ?>
318
- <?php printf( _wpsf__( 'There may also be %simportant updates to read about%s.' ), '<a href="http://icwp.io/27" id="fromIcwp" title="'._wpsf__( 'WordPress Simple Firewall' ).'" target="_blank">', '</a>' ); ?>
319
- </p>
320
- </h4>
321
- <input type="submit" value="<?php _wpsf_e( 'Okay, show me the dashboard' ); ?>" name="submit" class="button" style="float:left; margin-bottom:10px;">
322
- <div style="clear:both;"></div>
323
- </form>
324
- <?php
325
- $sNotice = ob_get_contents();
326
- ob_end_clean();
327
- return $sNotice;
328
- }
329
 
330
- /**
331
- * @return string|void
332
- */
333
- protected function getAdminNoticeHtml_MailingListSignup() {
 
334
 
335
- $nDays = $this->getInstallationDays();
336
- if ( $nDays < 2 ) {
337
- return '';
 
 
338
  }
339
- $sMetaFlag = $this->doPluginPrefix( 'hide_mailing_list_signup' );
340
-
341
- ob_start(); ?>
342
- <!-- Begin MailChimp Signup Form -->
343
- <div id="mc_embed_signup">
344
- <form class="form form-inline" action="http://hostliketoast.us2.list-manage1.com/subscribe/post?u=e736870223389e44fb8915c9a&amp;id=0e1d527259" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
345
- <p>The WordPress Simple Firewall team has launched a education initiative to raise awareness of WordPress security and to provide further help with the WordPress Simple Firewall plugin. Get Involved here:</p>
346
- <input type="text" value="" name="EMAIL" class="required email" id="mce-EMAIL" placeholder="Your Email" />
347
- <input type="text" value="" name="FNAME" class="" id="mce-FNAME" placeholder="Your Name" />
348
- <input type="hidden" value="<?php echo $nDays; ?>" name="DAYS" class="" id="mce-DAYS" />
349
- <input type="submit" value="Get The News" name="subscribe" id="mc-embedded-subscribe" class="button" />
350
- <a href="<?php echo $this->getUrl_PluginDashboard().'&'.$sMetaFlag.'=1';?>">Dismiss</a>
351
- <div id="mce-responses" class="clear">
352
- <div class="response" id="mce-error-response" style="display:none"></div>
353
- <div class="response" id="mce-success-response" style="display:none"></div>
354
- </div> <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
355
- <div style="position: absolute; left: -5000px;"><input type="text" name="b_e736870223389e44fb8915c9a_0e1d527259" tabindex="-1" value=""></div>
356
- <div class="clear"></div>
357
- </form>
358
- </div>
359
-
360
- <!--End mc_embed_signup-->
361
- <?php
362
- $sNotice = ob_get_contents();
363
- ob_end_clean();
364
- return $sNotice;
365
- }
366
 
367
- protected function getAdminNoticeHtml_OptionsUpdated() {
368
- $sAdminFeedbackNotice = $this->oPluginOptions->getOpt( 'feedback_admin_notice' );
369
- if ( !empty( $sAdminFeedbackNotice ) ) {
370
- $sNotice = '<p>'.$sAdminFeedbackNotice.'</p>';
371
- return $sNotice;
372
- $this->oPluginOptions->setOpt( 'feedback_admin_notice', '' );
373
  }
374
- }
375
 
376
- /**
377
- *
378
- */
379
- protected function getShowAdminNotices() {
380
- return $this->oPluginOptions->getOpt('enable_upgrade_admin_notice') == 'Y';
381
- }
382
 
383
- /**
384
- * @return int
385
- */
386
- protected function getInstallationDays() {
387
- $nTimeInstalled = $this->oPluginOptions->getOpt( 'installation_time' );
388
- if ( empty($nTimeInstalled) ) {
389
- return 0;
 
 
390
  }
391
- return round( ( time() - $nTimeInstalled ) / DAY_IN_SECONDS );
392
- }
393
 
394
- protected function getAdminBarNodes() {
395
- return array(); //disabled for now
396
- $aMenu = array(
397
- 'id' => self::$sOptionPrefix.'admin_menu',
398
- 'title' => '<span class="pluginlogo_16">&nbsp;</span>'._wpsf__('Firewall').'',
399
- 'href' => 'bob',
400
- );
401
- return array( $aMenu );
402
- }
 
 
 
 
 
 
403
 
404
- public function onWpDeactivatePlugin() {
405
- if ( $this->getFeatureHandler_MainPlugin()->getOpt( 'delete_on_deactivate' ) == 'Y' && current_user_can( $this->oPluginVo->getBasePermissions() ) ) {
406
- do_action( $this->doPluginPrefix( 'delete_plugin_options' ) );
 
 
407
  }
408
- }
409
 
410
- /**
411
- * @return ICWP_WPSF_FeatureHandler_Plugin|null
412
- */
413
- public function getFeatureHandler_MainPlugin() {
414
- return $this->loadFeatureHandler( 'plugin' );
415
- }
416
 
417
- /**
418
- * @return ICWP_WPSF_FeatureHandler_AdminAccessRestriction|null
419
- */
420
- public function getFeatureHandler_AdminAccessRestriction() {
421
- return $this->loadFeatureHandler( 'admin_access_restriction' );
422
- }
423
 
424
- /**
425
- * @return ICWP_WPSF_FeatureHandler_AdminAccessRestriction|null
426
- */
427
- public function getProcessor_AdminAccessRestriction() {
428
- return $this->getFeatureHandler_AdminAccessRestriction()->getProcessor();
429
- }
 
430
 
431
- /**
432
- * @return ICWP_WPSF_FirewallProcessor|null
433
- */
434
- public function getProcessor_Firewall() {
435
- $this->loadFeatureHandler( 'firewall' );
436
- return $this->oFirewallOptions->getProcessor();
437
- }
438
 
439
- /**
440
- * @return ICWP_WPSF_LoginProtectProcessor|null
441
- */
442
- public function getProcessor_LoginProtect() {
443
- $this->loadFeatureHandler( 'login_protect' );
444
- return $this->oLoginProtectOptions->getProcessor();
445
- }
446
 
447
- /**
448
- * @return ICWP_WPSF_AutoupdatesProcessor|null
449
- */
450
- public function getProcessor_Autoupdates() {
451
- $this->loadFeatureHandler( 'autoupdates' );
452
- return $this->oAutoupdatesOptions->getProcessor();
453
- }
454
 
455
- /**
456
- * @return ICWP_WPSF_PrivacyProtectProcessor|null
457
- */
458
- public function getProcessor_PrivacyProtect() {
459
- $this->loadFeatureHandler( 'privacy_protect' );
460
- return $this->oPrivacyProtectOptions->getProcessor();
461
- }
462
 
463
- /**
464
- * @return ICWP_WPSF_LoggingProcessor|null
465
- */
466
- public function getProcessor_Logging() {
467
- $this->loadFeatureHandler( 'logging' );
468
- return $this->oLoggingOptions->getProcessor();
469
- }
470
 
471
- /**
472
- * @return ICWP_WPSF_EmailProcessor|null
473
- */
474
- public function getProcessor_Email() {
475
- return $this->oPluginOptions->getEmailProcessor();
 
476
  }
477
- }
478
 
479
  endif;
 
 
 
1
  <?php
 
2
  /**
3
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
20
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21
  */
22
 
23
+ require_once( dirname(__FILE__).ICWP_DS.'src'.ICWP_DS.'icwp-pure-base.php' );
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
  if ( !class_exists('ICWP_Wordpress_Simple_Firewall') ):
26
 
27
+ class ICWP_Wordpress_Simple_Firewall extends ICWP_Pure_Base_V6 {
28
+
29
+ /**
30
+ * @var ICWP_WPSF_FeatureHandler_Plugin
31
+ */
32
+ protected $oFeatureHandlerPlugin;
33
+ /**
34
+ * @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction
35
+ */
36
+ protected $oFeatureHandlerAdminAccessRestriction;
37
+ /**
38
+ * @var ICWP_WPSF_FeatureHandler_Firewall
39
+ */
40
+ protected $oFeatureHandlerFirewall;
41
+ /**
42
+ * @var ICWP_WPSF_FeatureHandler_LoginProtect
43
+ */
44
+ protected $oFeatureHandlerLoginProtect;
45
+
46
+ /**
47
+ * @var ICWP_WPSF_FeatureHandler_PrivacyProtect
48
+ */
49
+ protected $oFeatureHandlerPrivacyProtect;
50
+
51
+ /**
52
+ * @var ICWP_WPSF_FeatureHandler_AuditTrail
53
+ */
54
+ protected $oFeatureHandlerAuditTrail;
55
+
56
+ /**
57
+ * @var ICWP_WPSF_FeatureHandler_CommentsFilter
58
+ */
59
+ protected $oFeatureHandlerCommentsFilter;
60
+
61
+ /**
62
+ * @var ICWP_WPSF_FeatureHandler_Lockdown
63
+ */
64
+ protected $oFeatureHandlerLockdown;
65
+
66
+ /**
67
+ * @var ICWP_WPSF_FeatureHandler_Autoupdates
68
+ */
69
+ protected $oFeatureHandlerAutoupdates;
70
+
71
+ /**
72
+ * @var ICWP_WPSF_FeatureHandler_Email
73
+ */
74
+ protected $oFeatureHandlerEmail;
75
+
76
+ /**
77
+ * @var ICWP_WPSF_FeatureHandler_Logging
78
+ */
79
+ protected $oFeatureHandlerLogging;
80
+
81
+ /**
82
+ */
83
+ public function __construct( ICWP_WPSF_Plugin_Controller $oPluginVo ) {
84
+ parent::__construct( $oPluginVo );
85
+
86
+ $this->loadAllFeatures();
87
+ add_filter( $this->doPluginPrefix( 'has_permission_to_view' ), array( $this, 'hasPermissionToView' ) );
88
+ add_filter( $this->doPluginPrefix( 'has_permission_to_submit' ), array( $this, 'hasPermissionToSubmit' ) );
89
+ add_filter( $this->doPluginPrefix( 'plugin_update_message' ), array( $this, 'getPluginsListUpdateMessage' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
 
 
91
 
92
+ public function onWpActivatePlugin() {
93
+ $this->loadAllFeatures( true, true );
 
94
  }
95
 
96
+ /**
97
+ * @return ICWP_WPSF_FeatureHandler_Plugin
98
+ */
99
+ protected function loadCorePluginFeature() {
100
+ if ( isset( $this->oPluginOptions ) ) {
101
+ return $this->oPluginOptions;
102
+ }
103
+ return $this->loadFeatureHandler( 'plugin' );
104
  }
 
 
105
 
106
+ /**
107
+ * @param bool $fRecreate
108
+ * @param bool $fFullBuild
109
+ * @return bool
110
+ */
111
+ protected function loadAllFeatures( $fRecreate = false, $fFullBuild = false ) {
112
+
113
+ $oMainPluginFeature = $this->loadCorePluginFeature();
114
+ $aPluginFeatures = $oMainPluginFeature->getActivePluginFeatures();
115
+
116
+ $fSuccess = true;
117
+ foreach( $aPluginFeatures as $sSlug => $sStorageKey ) {
118
+ try {
119
+ $this->loadFeatureHandler( $sSlug, $fRecreate, $fFullBuild );
120
+ $fSuccess = true;
121
+ }
122
+ catch( Exception $oE ) {
123
+ wp_die( $oE->getMessage() );
124
+ }
125
+ }
126
+ return $fSuccess;
127
  }
 
 
128
 
129
+ /**
130
+ * @param string $sFeatureSlug
131
+ * @param bool $fRecreate
132
+ * @param bool $fFullBuild
133
+ * @return mixed
134
+ * @throws Exception
135
+ */
136
+ protected function loadFeatureHandler( $sFeatureSlug, $fRecreate = false, $fFullBuild = false ) {
 
137
 
138
+ $sFeatureName = str_replace( ' ', '', ucwords( str_replace( '_', ' ', $sFeatureSlug ) ) );
139
+ $sOptionsVarName = sprintf( 'oFeatureHandler%s', $sFeatureName ); // e.g. oFeatureHandlerOptions
 
 
 
 
 
 
140
 
141
+ if ( isset( $this->{$sOptionsVarName} ) ) {
142
+ return $this->{$sOptionsVarName};
143
+ }
 
 
144
 
145
+ $sSourceFile = $this->getController()->getSourceDir( sprintf( 'icwp-optionshandler-%s.php', $sFeatureSlug ) ); // e.g. icwp-optionshandler-plugin.php
146
+ $sClassName = sprintf( 'ICWP_WPSF_FeatureHandler_%s', $sFeatureName ); // e.g. ICWP_WPSF_FeatureHandler_Plugin
 
 
147
 
148
+ require_once( $sSourceFile );
149
+ if ( $fRecreate || !isset( $this->{$sOptionsVarName} ) ) {
150
+ $this->{$sOptionsVarName} = new $sClassName( $this->getController() );
151
+ }
152
+ if ( $fFullBuild ) {
153
+ $this->{$sOptionsVarName}->buildOptions();
154
+ }
155
+ return $this->{$sOptionsVarName};
 
 
 
 
 
 
 
 
 
156
  }
 
 
 
 
 
 
 
 
 
 
 
157
 
158
+ /**
159
+ * @param array $aItems
160
+ * @return array $aItems
161
+ */
162
+ public function filter_addExtraAdminMenuItems( $aItems ) {
163
+ $aItems[ _wpsf__('Firewall Log' ) ] = array( 'Firewall Log', $this->doPluginPrefix('firewall_log'), array( $this, 'onDisplayAll' ) );
164
+ // $aItems[ _wpsf__('Audit Trail Viewer' ) ] = array( 'Audit Trail Viewer', $this->doPluginPrefix('audit_trail_viewer'), array( $this, 'onDisplayAll' ) );
165
+ return $aItems;
166
+ }
167
 
168
+ /**
169
+ * Displaying all views now goes through this central function and we work out
170
+ * what to display based on the name of current hook/filter being processed.
171
+ */
172
+ public function onDisplayAll() {
 
 
173
 
174
+ if ( !$this->hasPermissionToView() ) {
175
+ $this->onDisplayAccessKeyRequest();
176
+ return;
177
+ }
178
 
179
+ // Just to ensure the nag bar disappears if/when they visit the dashboard
180
+ // regardless of clicking the button.
181
+ $this->updateVersionUserMeta();
182
+
183
+ $sPrefix = str_replace(' ', '-', strtolower( $this->getController()->getAdminMenuTitle() ) ) .'_page_'.$this->getPluginPrefix().'-';
184
+ $sCurrent = str_replace( $sPrefix, '', current_filter() );
185
+
186
+ switch( $sCurrent ) {
187
+ case 'privacy_protect_log' :
188
+ $this->onDisplayPrivacyProtectLog();
189
+ break;
190
+ case 'firewall_log' :
191
+ $this->onDisplayFirewallLog();
192
+ break;
193
+ case 'audit_trail_viewer' :
194
+ $this->onDisplayAuditTrailViewer();
195
+ break;
196
+ default:
197
+ $this->getFeatureHandler_MainPlugin()->displayFeatureConfigPage();
198
+ break;
199
+ }
200
+ }
201
 
202
+ protected function onDisplayPrivacyProtectLog() {
 
203
 
204
+ $oPrivacyProcessor = $this->getProcessor_PrivacyProtect();
205
+ $aData = array(
206
+ 'urlrequests_log' => $oPrivacyProcessor->getLogs( true )
207
+ );
208
+ $aData = array_merge( $this->getBaseDisplayData(), $aData );
209
+ $this->display( $this->doPluginPrefix( 'privacy_protect_log_index' ), $aData );
210
+ }
 
211
 
212
+ protected function onDisplayFirewallLog() {
 
213
 
214
+ $oFirewallHandler = $this->loadFeatureHandler( 'firewall' );
215
+ if ( $oFirewallHandler instanceof ICWP_WPSF_FeatureHandler_Firewall ) {
216
+ $aIpWhitelist = $oFirewallHandler->getOpt( 'ips_whitelist' );
217
+ $aIpBlacklist = $oFirewallHandler->getOpt( 'ips_blacklist' );
 
 
 
 
 
 
 
218
  }
219
 
220
+ $oLoggingProcessor = $this->getProcessor_Logging();
221
+ if ( $oLoggingProcessor instanceof ICWP_WPSF_Processor_Logging ) {
222
+ $aLogData = $oLoggingProcessor->getLogs( true );
 
223
  }
224
 
225
+ $aData = array(
226
+ 'sFeatureName' => _wpsf__('Firewall Log'),
227
+ 'firewall_log' => $aLogData,
228
+ 'ip_whitelist' => isset( $aIpWhitelist['ips'] )? $aIpWhitelist['ips'] : array(),
229
+ 'ip_blacklist' => isset( $aIpBlacklist['ips'] )? $aIpBlacklist['ips'] : array(),
230
+ );
231
+ $aData = array_merge( $this->getBaseDisplayData(), $aData );
232
+ $this->display( $this->doPluginPrefix( 'firewall_log_index' ), $aData );
233
  }
 
234
 
235
+ protected function onDisplayAuditTrailViewer() {
 
 
 
 
 
236
 
237
+ $oAuditTrail = $this->getProcessor_AuditTrail();
238
+ $aAuditData = $oAuditTrail->getAllAuditEntries();
 
239
 
240
+ $aAuditDataUsers = array();
241
+ $aAuditDataPlugins = array();
242
+ $aAuditDataThemes = array();
243
+ $aAuditDataWordpress = array();
244
+ $aAuditDataPosts = array();
245
+ foreach( $aAuditData as $aAudit ) {
246
+ if ( $aAudit['context'] == 'users' ) {
247
+ $aAuditDataUsers[] = $aAudit;
248
+ }
249
+ if ( $aAudit['context'] == 'plugins' ) {
250
+ $aAuditDataPlugins[] = $aAudit;
251
+ }
252
+ if ( $aAudit['context'] == 'themes' ) {
253
+ $aAuditDataThemes[] = $aAudit;
254
+ }
255
+ if ( $aAudit['context'] == 'wordpress' ) {
256
+ $aAuditDataWordpress[] = $aAudit;
257
+ }
258
+ if ( $aAudit['context'] == 'posts' ) {
259
+ $aAuditDataPosts[] = $aAudit;
260
+ }
261
+ }
262
 
263
+ $aData = array(
264
+ 'sFeatureName' => _wpsf__('Audit Trail Viewer'),
265
+ 'aAuditDataUsers' => $aAuditDataUsers,
266
+ 'aAuditDataPlugins' => $aAuditDataPlugins,
267
+ 'aAuditDataThemes' => $aAuditDataThemes,
268
+ 'aAuditDataWordpress' => $aAuditDataWordpress,
269
+ 'aAuditDataPosts' => $aAuditDataPosts
270
+ );
271
+ $aData = array_merge( $this->getBaseDisplayData(), $aData );
272
+ $this->display( $this->doPluginPrefix( 'audit_trail_viewer_index' ), $aData );
273
  }
274
 
275
+ public function onWpAdminInit() {
276
+ parent::onWpAdminInit();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
 
278
+ if ( $this->getController()->getIsValidAdminArea() ) {
279
+ $oDp = $this->loadDataProcessor();
280
+ $oWp = $this->loadWpFunctionsProcessor();
281
 
282
+ $sRedirect = $oDp->FetchPost( 'redirect_page' );
283
+ $sRedirect = empty( $sRedirect ) ? $this->getController()->getPluginUrl_AdminPage() : $sRedirect;
284
+ //Someone clicked the button to acknowledge the update
285
+ if ( $oDp->FetchRequest( $this->doPluginPrefix( 'hide_update_notice' ) ) == 1 ) {
286
+ $this->updateVersionUserMeta();
287
+ $oWp->doRedirect( $sRedirect );
288
+ }
289
 
290
+ if ( $oDp->FetchRequest( $this->doPluginPrefix( 'hide_translation_notice' ) ) == 1 ) {
291
+ $this->updateTranslationNoticeShownUserMeta();
292
+ $oWp->doRedirect( $sRedirect );
293
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
 
295
+ if ( $oDp->FetchRequest( $this->doPluginPrefix( 'hide_mailing_list_signup' ) ) == 1 ) {
296
+ $this->updateMailingListSignupShownUserMeta();
297
+ }
298
+ }
299
+ }
300
 
301
+ /**
302
+ * @return bool
303
+ */
304
+ protected function isShowMarketing() {
305
+ return apply_filters( $this->doPluginPrefix( 'show_marketing' ), true );
306
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
 
308
+ public function getPluginsListUpdateMessage( $sMessage ) {
309
+ return _wpsf__( 'Upgrade Now To Keep Your Firewall Up-To-Date With The Latest Features.' );
 
 
 
 
310
  }
 
311
 
312
+ /**
313
+ * @return bool
314
+ */
315
+ protected function getShowAdminNotices() {
316
+ return $this->loadCorePluginFeature()->getOpt( 'enable_upgrade_admin_notice' ) == 'Y';
317
+ }
318
 
319
+ /**
320
+ * @return int
321
+ */
322
+ protected function getInstallationDays() {
323
+ $nTimeInstalled = $this->loadCorePluginFeature()->getOpt( 'installation_time' );
324
+ if ( empty($nTimeInstalled) ) {
325
+ return 0;
326
+ }
327
+ return round( ( time() - $nTimeInstalled ) / DAY_IN_SECONDS );
328
  }
 
 
329
 
330
+ protected function getAdminBarNodes() {
331
+ return array(); //disabled for now
332
+ $aMenu = array(
333
+ 'id' => $this->doPluginOptionPrefix( 'admin_menu' ),
334
+ 'title' => '<span class="pluginlogo_16">&nbsp;</span>'._wpsf__('Firewall').'',
335
+ 'href' => 'bob',
336
+ );
337
+ return array( $aMenu );
338
+ }
339
+
340
+ public function onWpDeactivatePlugin() {
341
+ if ( $this->getFeatureHandler_MainPlugin()->getOpt( 'delete_on_deactivate' ) == 'Y' && current_user_can( $this->getController()->getBasePermissions() ) ) {
342
+ do_action( $this->doPluginPrefix( 'delete_plugin' ) );
343
+ }
344
+ }
345
 
346
+ /**
347
+ * @return ICWP_WPSF_FeatureHandler_Plugin|null
348
+ */
349
+ public function getFeatureHandler_MainPlugin() {
350
+ return $this->loadFeatureHandler( 'plugin' );
351
  }
 
352
 
353
+ /**
354
+ * @return ICWP_WPSF_FeatureHandler_AdminAccessRestriction|null
355
+ */
356
+ public function getFeatureHandler_AdminAccessRestriction() {
357
+ return $this->loadFeatureHandler( 'admin_access_restriction' );
358
+ }
359
 
360
+ /**
361
+ * @return ICWP_WPSF_FeatureHandler_AdminAccessRestriction|null
362
+ */
363
+ public function getProcessor_AdminAccessRestriction() {
364
+ return $this->getFeatureHandler_AdminAccessRestriction()->getProcessor();
365
+ }
366
 
367
+ /**
368
+ * @return ICWP_WPSF_Processor_Firewall|null
369
+ */
370
+ public function getProcessor_Firewall() {
371
+ $this->loadFeatureHandler( 'firewall' );
372
+ return $this->oFeatureHandlerFirewall->getProcessor();
373
+ }
374
 
375
+ /**
376
+ * @return ICWP_WPSF_Processor_LoginProtect|null
377
+ */
378
+ public function getProcessor_LoginProtect() {
379
+ $this->loadFeatureHandler( 'login_protect' );
380
+ return $this->oFeatureHandlerLoginProtect->getProcessor();
381
+ }
382
 
383
+ /**
384
+ * @return ICWP_WPSF_Processor_Autoupdates|null
385
+ */
386
+ public function getProcessor_Autoupdates() {
387
+ $this->loadFeatureHandler( 'autoupdates' );
388
+ return $this->oFeatureHandlerAutoupdates->getProcessor();
389
+ }
390
 
391
+ /**
392
+ * @return ICWP_WPSF_Processor_PrivacyProtect|null
393
+ */
394
+ public function getProcessor_PrivacyProtect() {
395
+ $this->loadFeatureHandler( 'privacy_protect' );
396
+ return $this->oFeatureHandlerPrivacyProtect->getProcessor();
397
+ }
398
 
399
+ /**
400
+ * @return ICWP_WPSF_Processor_AuditTrail|null
401
+ */
402
+ public function getProcessor_AuditTrail() {
403
+ $this->loadFeatureHandler( 'audit_trail' );
404
+ return $this->oFeatureHandlerAuditTrail->getProcessor();
405
+ }
406
 
407
+ /**
408
+ * @return ICWP_WPSF_Processor_Logging|null
409
+ */
410
+ public function getProcessor_Logging() {
411
+ $this->loadFeatureHandler( 'logging' );
412
+ return $this->oFeatureHandlerLogging->getProcessor();
413
+ }
414
 
415
+ /**
416
+ * @return ICWP_WPSF_Processor_Email|null
417
+ */
418
+ public function getProcessor_Email() {
419
+ return $this->oFeatureHandlerEmail->getEmailProcessor();
420
+ }
421
  }
 
422
 
423
  endif;
424
+
425
+ require_once( 'icwp-plugin-controller.php');
426
+ $oICWP_Wpsf = new ICWP_Wordpress_Simple_Firewall( ICWP_WPSF_Plugin_Controller::GetInstance( ICWP_WPSF_Spec::GetInstance() ) );
icwp-wpsf.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WordPress Simple Firewall
4
  * Plugin URI: http://icwp.io/2f
5
  * Description: A Simple WordPress Firewall
6
- * Version: 3.0.0
7
  * Text Domain: wp-simple-firewall
8
  * Author: iControlWP
9
  * Author URI: http://icwp.io/2e
@@ -13,8 +13,7 @@
13
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
14
  * All rights reserved.
15
  *
16
- * "WordPress Simple Firewall" is
17
- * distributed under the GNU General Public License, Version 2,
18
  * June 1991. Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin
19
  * St, Fifth Floor, Boston, MA 02110, USA
20
  *
@@ -30,9 +29,21 @@
30
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
  */
32
 
33
- require_once( dirname(__FILE__).'/icwp-wpsf-main.php' );
 
 
34
 
35
- class ICWP_Wordpress_Simple_Firewall_Plugin {
 
 
 
 
 
 
 
 
 
 
36
 
37
  /**
38
  * @const string
@@ -47,77 +58,60 @@ class ICWP_Wordpress_Simple_Firewall_Plugin {
47
  /**
48
  * @var string
49
  */
50
- private static $sVersion = '3.0.0';
51
-
52
- /**
53
- * @var string
54
- */
55
- private static $sParentSlug = 'icwp';
56
 
57
  /**
58
  * @var string
59
  */
60
- private static $sPluginSlug = 'wpsf';
61
 
62
  /**
63
  * @var string
64
  */
65
- private static $sHumanName = 'WordPress Simple Firewall';
66
 
67
  /**
68
  * @var string
69
  */
70
- private static $sMenuTitleName = 'Simple Firewall';
71
 
72
  /**
73
  * @var string
74
  */
75
- private static $sTextDomain = 'wp-simple-firewall';
76
 
77
  /**
78
  * @var string
79
  */
80
- private static $sBasePermissions = 'manage_options';
81
 
82
  /**
83
  * @var string
84
  */
85
- private static $sWpmsNetworkAdminOnly = true;
86
 
87
  /**
88
  * @var string
89
  */
90
- private static $sRootFile = '';
91
 
92
  /**
93
  * @var string
94
  */
95
- private static $fAutoUpgrade = false;
96
 
97
  /**
98
  * @var string
99
  */
100
- private static $aFeatures = array(
101
- 'plugin',
102
- 'logging',
103
- 'email',
104
- 'admin_access_restriction',
105
- 'firewall',
106
- 'login_protect',
107
- 'user_management',
108
- 'comments_filter',
109
- // 'privacy_protect',
110
- 'autoupdates',
111
- 'lockdown'
112
- );
113
 
114
  /**
115
- * @var ICWP_Wordpress_Simple_Firewall_Plugin
116
  */
117
  public static $oInstance;
118
 
119
  /**
120
- * @return ICWP_Wordpress_Simple_Firewall_Plugin
121
  */
122
  public static function GetInstance() {
123
  if ( !isset( self::$oInstance ) ) {
@@ -129,9 +123,7 @@ class ICWP_Wordpress_Simple_Firewall_Plugin {
129
  /**
130
  */
131
  private function __construct() {
132
- if ( empty( self::$sRootFile ) ) {
133
- self::$sRootFile = __FILE__;
134
- }
135
  }
136
 
137
  /**
@@ -149,34 +141,17 @@ class ICWP_Wordpress_Simple_Firewall_Plugin {
149
  }
150
 
151
  /**
152
- * @param string
153
- * @return string
154
- */
155
- public function getFullPluginPrefix( $sGlue = '-' ) {
156
- return sprintf( '%s%s%s', self::$sParentSlug, $sGlue, self::$sPluginSlug );
157
- }
158
-
159
- /**
160
- * @param string
161
- * @return string
162
- */
163
- public function getFeatures() {
164
- return self::$aFeatures;
165
- }
166
-
167
- /**
168
- * @param string
169
  * @return string
170
  */
171
- public function getOptionStoragePrefix() {
172
- return $this->getFullPluginPrefix( '_' ).'_';
173
  }
174
 
175
  /**
176
  * @return string
177
  */
178
- public function getHumanName() {
179
- return self::$sHumanName;
180
  }
181
 
182
  /**
@@ -200,15 +175,6 @@ class ICWP_Wordpress_Simple_Firewall_Plugin {
200
  return self::$sPluginSlug;
201
  }
202
 
203
- /**
204
- * get the root directory for the plugin with the trailing slash
205
- *
206
- * @return string
207
- */
208
- public function getRootDir() {
209
- return dirname( $this->getRootFile() ).ICWP_DS;
210
- }
211
-
212
  /**
213
  * @return string
214
  */
@@ -216,15 +182,6 @@ class ICWP_Wordpress_Simple_Firewall_Plugin {
216
  return self::$sRootFile;
217
  }
218
 
219
- /**
220
- * get the directory for the plugin view with the trailing slash
221
- *
222
- * @return string
223
- */
224
- public function getSourceDir() {
225
- return $this->getRootDir().self::SrcDir.ICWP_DS;
226
- }
227
-
228
  /**
229
  * @return string
230
  */
@@ -238,15 +195,5 @@ class ICWP_Wordpress_Simple_Firewall_Plugin {
238
  public function getVersion() {
239
  return self::$sVersion;
240
  }
241
-
242
- /**
243
- * get the directory for the plugin view with the trailing slash
244
- *
245
- * @return string
246
- */
247
- public function getViewDir() {
248
- return $this->getRootDir().self::ViewDir.ICWP_DS;
249
- }
250
  }
251
-
252
- $oICWP_Wpsf = new ICWP_Wordpress_Simple_Firewall( ICWP_Wordpress_Simple_Firewall_Plugin::GetInstance() );
3
  * Plugin Name: WordPress Simple Firewall
4
  * Plugin URI: http://icwp.io/2f
5
  * Description: A Simple WordPress Firewall
6
+ * Version: 3.5.5
7
  * Text Domain: wp-simple-firewall
8
  * Author: iControlWP
9
  * Author URI: http://icwp.io/2e
13
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
14
  * All rights reserved.
15
  *
16
+ * "WordPress Simple Firewall" is distributed under the GNU General Public License, Version 2,
 
17
  * June 1991. Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin
18
  * St, Fifth Floor, Boston, MA 02110, USA
19
  *
29
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
  */
31
 
32
+ if ( !defined('ICWP_DS') ) {
33
+ define( 'ICWP_DS', DIRECTORY_SEPARATOR );
34
+ }
35
 
36
+ if ( !function_exists( '_wpsf_e' ) ) {
37
+ function _wpsf_e( $insStr ) {
38
+ _e( $insStr, 'wp-simple-firewall' );
39
+ }
40
+ }
41
+ if ( !function_exists( '_wpsf__' ) ) {
42
+ function _wpsf__( $insStr ) {
43
+ return __( $insStr, 'wp-simple-firewall' );
44
+ }
45
+ }
46
+ class ICWP_WPSF_Spec {
47
 
48
  /**
49
  * @const string
58
  /**
59
  * @var string
60
  */
61
+ protected static $fLoggingEnabled = true;
 
 
 
 
 
62
 
63
  /**
64
  * @var string
65
  */
66
+ private static $sVersion = '3.5.5';
67
 
68
  /**
69
  * @var string
70
  */
71
+ private static $sParentSlug = 'icwp';
72
 
73
  /**
74
  * @var string
75
  */
76
+ private static $sPluginSlug = 'wpsf';
77
 
78
  /**
79
  * @var string
80
  */
81
+ private static $sRootFile;
82
 
83
  /**
84
  * @var string
85
  */
86
+ private static $sHumanName = 'WordPress Simple Firewall';
87
 
88
  /**
89
  * @var string
90
  */
91
+ private static $sMenuTitleName = 'Simple Firewall';
92
 
93
  /**
94
  * @var string
95
  */
96
+ private static $sTextDomain = 'wp-simple-firewall';
97
 
98
  /**
99
  * @var string
100
  */
101
+ private static $sBasePermissions = 'manage_options';
102
 
103
  /**
104
  * @var string
105
  */
106
+ private static $sWpmsNetworkAdminOnly = true;
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  /**
109
+ * @var ICWP_WPSF_Spec
110
  */
111
  public static $oInstance;
112
 
113
  /**
114
+ * @return ICWP_WPSF_Spec
115
  */
116
  public static function GetInstance() {
117
  if ( !isset( self::$oInstance ) ) {
123
  /**
124
  */
125
  private function __construct() {
126
+ self::$sRootFile = __FILE__;
 
 
127
  }
128
 
129
  /**
141
  }
142
 
143
  /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  * @return string
145
  */
146
+ public function getHumanName() {
147
+ return self::$sHumanName;
148
  }
149
 
150
  /**
151
  * @return string
152
  */
153
+ public function getIsLoggingEnabled() {
154
+ return self::$fLoggingEnabled;
155
  }
156
 
157
  /**
175
  return self::$sPluginSlug;
176
  }
177
 
 
 
 
 
 
 
 
 
 
178
  /**
179
  * @return string
180
  */
182
  return self::$sRootFile;
183
  }
184
 
 
 
 
 
 
 
 
 
 
185
  /**
186
  * @return string
187
  */
195
  public function getVersion() {
196
  return self::$sVersion;
197
  }
 
 
 
 
 
 
 
 
 
198
  }
199
+ require_once( 'icwp-wpsf-main.php' );
 
languages/wp-simple-firewall-es_ES.mo CHANGED
Binary file
languages/wp-simple-firewall-fr_FR.mo ADDED
Binary file
languages/wp-simple-firewall-pt_BR.mo CHANGED
Binary file
mode.login_throttled DELETED
File without changes
readme.txt CHANGED
@@ -3,10 +3,10 @@ Contributors: paultgoodchild, dlgoodchild
3
  Donate link: http://icwp.io/q
4
  License: GPLv3
5
  License URI: http://www.gnu.org/licenses/gpl.html
6
- Tags: WordPress Firewall, protection, whitelist, blacklist, two-factor authentication, GASP, comment spam, automatic updates, lockdown, login, hack, login
7
  Requires at least: 3.2.0
8
- Tested up to: 3.9
9
- Stable tag: 3.0.0
10
 
11
  Complete and Simple WordPress Security. Unrestricted, Easy, No Premium Features.
12
 
@@ -225,9 +225,83 @@ You can either manually upgrade, or WordPress will handle it in due course.
225
 
226
  == Changelog ==
227
 
228
- = TODO =
229
 
230
- * CHANGE: Interface to give a better "At-A-Glance" Dashboard summary view, that also allows you to turn on/off core features.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
 
232
  = 3.0.0 =
233
 
3
  Donate link: http://icwp.io/q
4
  License: GPLv3
5
  License URI: http://www.gnu.org/licenses/gpl.html
6
+ Tags: WordPress Firewall, audit trail, protection, whitelist, blacklist, two-factor authentication, GASP, comment spam, automatic updates, lockdown, login, hack, login
7
  Requires at least: 3.2.0
8
+ Tested up to: 4.0
9
+ Stable tag: 3.5.5
10
 
11
  Complete and Simple WordPress Security. Unrestricted, Easy, No Premium Features.
12
 
225
 
226
  == Changelog ==
227
 
228
+ * KNOWN ISSUE: Login Protection logs are not being properly created.
229
 
230
+ = 4.0.0 =
231
+
232
+ * ADDED: New Feature - Audit Trail ( Coming Soon! )
233
+
234
+ = 3.5.5 =
235
+
236
+ * ADDED: Better admin notifications for events such as options saving etc.
237
+ * CHANGE: Some plugin styling to highlight features and options better.
238
+ * FIXED: Small bug with options default values.
239
+
240
+ = 3.5.3 =
241
+
242
+ * ADDED: A warning message on the WordPress admin if the "forceOff" override is active.
243
+ * CHANGED: The 'forceOff' system is now temporary - i.e. it doesn't save the configuration, and so once this file is removed, the plugin returns to the settings specified.
244
+ * CHANGED: The 'forceOn' option is now removed.
245
+ * FIXED: Problems with certain hosting environments reading in files with the ".yaml" extension - [support ref](https://wordpress.org/support/topic/yaml-breaks-plugin)
246
+ * FIXED: Small issue where when the file system paths change, some variables don't update properly.
247
+
248
+ = 3.5.0 =
249
+
250
+ * CHANGED: Plugin features are now configured [using YAML](https://github.com/mustangostang/spyc/) - no more in-PHP configuration.
251
+ * REMOVED: A few options from User Sessions Management as they were unnecessary.
252
+ * CHANGED: Database storing tables now have consistent naming.
253
+ * FIXED: Issue with User Sessions Management where '0' was specified for session length, resulting in lock out.
254
+ * FIXED: Firewall log gathering.
255
+ * FIXED: Various PHP warning notices.
256
+
257
+ = 3.4.0 =
258
+
259
+ * ADDED: Option to limit number of simultaneous sessions per WordPress user login name (User Management section)
260
+
261
+ = 3.3.0 =
262
+
263
+ * ADDED: Option to send notification when an administrator user logs in successfully (under User Management menu).
264
+ * CHANGED: Refactoring for how GET and POST data is retrieved
265
+
266
+ = 3.2.1 =
267
+
268
+ * FIXED: Custom Comment Filter message problem when using more than one substitution. [ref](http://wordpress.org/support/topic/warning-sprintf-too-few-arguments-in-hometnrastropublic_htmlwpwp-conten?replies=8#post-5927337)
269
+
270
+ = 3.2.0 =
271
+
272
+ * ADDED: Options to allow by-pass XML-RPC so as to be compatible with WordPress iPhone/Android apps.
273
+ * UPDATED: Login screen message when you're forced logged-out due to 2-factor auth failure on IP or cookie.
274
+ * CHANGED: Tweaked method for setting admin access protection on/off
275
+ * CHANGED: comment filtering code refactoring.
276
+ * FIXED: Options that were "multiple selects" weren't saving correctly
277
+
278
+ = 3.1.5 =
279
+
280
+ * FIX: Where some comments would fail GASP comment token checking.
281
+
282
+ = 3.1.4 =
283
+
284
+ * FIX: Logout URL parameters are now generated correctly so that the correct messages are shown.
285
+ * CHANGED: small optimizations and code refactoring.
286
+ * UPDATED: a few translation files based on the latest available contributions.
287
+
288
+ = 3.1.3 =
289
+
290
+ * FIX: issue with login cooldown timeouts not being updated where admin access restriction is in place.
291
+
292
+ = 3.1.2 =
293
+
294
+ * FIX: auto-updates feature not loading
295
+ * FIX: simplified implementation of login protection feature to reduce possibility for bugs/lock-outs
296
+ * FIX: auto-forwarding for wp-login.php was preventing user logout
297
+
298
+ = 3.1.0 =
299
+
300
+ * ADDED: option to check the logged-in user session only on WordPress admin pages (now the default setting)
301
+ * ADDED: option to auto-forward to the WordPress dashboard when you go to wp-login.php and you're already logged in.
302
+ * ADDED: message to login screen when no user session is found
303
+ * CHANGED: does not verify session when performing AJAX request. (need to build appropriate AJAX response)
304
+ * FIX: for wp_login action not passing second argument
305
 
306
  = 3.0.0 =
307
 
resources/css/global-plugin.css ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @CHARSET "ISO-8859-1";
2
+
3
+ .wrap .icwp-admin-notice {
4
+ padding: 13px 20px;
5
+ border: 1px solid rgba(240, 165, 4, 0.56);
6
+ background-color: rgba(255, 227, 167, 0.25);
7
+ border-right-width: 5px;
8
+ border-left-width: 5px;
9
+ }
10
+
11
+ .wrap .icwp-admin-notice p {
12
+ text-shadow: -1px -1px 0px rgba(255,255,255,0.4);
13
+ }
14
+ .wrap .icwp-admin-notice.updated p {
15
+ color: rgba(155, 107, 5, 1);
16
+ }
17
+ .wrap .icwp-admin-notice form {
18
+ margin: 0;
19
+ }
20
+ .wrap .icwp-admin-notice .button {
21
+ margin: 10px 0 7px;
22
+ }
23
+ .wrap .icwp-admin-notice .button:hover {
24
+ text-decoration: none;
25
+ }
26
+
27
+ .wrap .error.icwp-admin-notice {
28
+ border-color: rgba(240, 51, 4, 0.56);
29
+ background-color: rgba(255, 185, 167, 0.25);
30
+ }
31
+ .wrap .error.icwp-admin-notice h3 {
32
+ color: rgba(199, 41, 0, 1);
33
+ }
resources/css/plugin.css CHANGED
@@ -20,6 +20,9 @@
20
  vertical-align: middle;
21
  width: 48px;
22
  }
 
 
 
23
  .wrap .icon32 {
24
  width: 32px;
25
  }
@@ -30,6 +33,7 @@
30
  }
31
  /* Form elements */
32
  .bootstrap-wpadmin form fieldset {
 
33
  }
34
  .bootstrap-wpadmin .label {
35
  vertical-align: baseline !important;
@@ -66,6 +70,38 @@ p.code-description {
66
  padding: 10px 20px;
67
  }
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  /** LESS PAGE **/
70
  .enabled_section {
71
  opacity: 1.0;
@@ -84,7 +120,7 @@ p.code-description {
84
  .form-horizontal legend {
85
  border-bottom: 1px dashed #aaa;
86
  margin-bottom: 8px;
87
- margin-top: 30px;
88
  }
89
  .form-horizontal .item_group .control-group {
90
  margin-bottom: 0;
20
  vertical-align: middle;
21
  width: 48px;
22
  }
23
+ .plugin_update_message {
24
+ color: #dd3333;
25
+ }
26
  .wrap .icon32 {
27
  width: 32px;
28
  }
33
  }
34
  /* Form elements */
35
  .bootstrap-wpadmin form fieldset {
36
+ width: 80%;
37
  }
38
  .bootstrap-wpadmin .label {
39
  vertical-align: baseline !important;
70
  padding: 10px 20px;
71
  }
72
 
73
+ .row.option_section_row {
74
+ margin-left: 0px;
75
+ }
76
+ .row.option_section_row.primary_section {
77
+ background-color: #f9f9f9;
78
+ border: 1px solid transparent;
79
+ box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);
80
+ margin-bottom: 20px;
81
+ padding-bottom: 30px;
82
+ }
83
+ /*
84
+ .row.option_section_row.primary_section > div {
85
+ background-color: #f9f9f9;
86
+ border: 1px solid #ddd;
87
+ margin-bottom: 30px;
88
+ margin-top: 10px;
89
+ padding: 5px 30px 30px;
90
+ }
91
+ .row.option_section_row.non_primary_section > div {
92
+ margin-left: 0px;
93
+ }*/
94
+
95
+ .well.admin_access_restriction_form {
96
+ background-color: #fbfbfb;
97
+ border: 1px solid #ccc;
98
+ box-shadow: none;
99
+ }
100
+
101
+ .well.admin_access_restriction_form .form-actions {
102
+ background-color: #fbfbfb;
103
+ }
104
+
105
  /** LESS PAGE **/
106
  .enabled_section {
107
  opacity: 1.0;
120
  .form-horizontal legend {
121
  border-bottom: 1px dashed #aaa;
122
  margin-bottom: 8px;
123
+ margin-top: 10px;
124
  }
125
  .form-horizontal .item_group .control-group {
126
  margin-bottom: 0;
resources/js/bootstrap.min.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ /*!
2
+ * Bootstrap.js by @fat & @mdo
3
+ * Copyright 2012 Twitter, Inc.
4
+ * http://www.apache.org/licenses/LICENSE-2.0.txt
5
+ */
6
+ !function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(".dropdown-backdrop").remove(),e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||("ontouchstart"in document.documentElement&&e('<div class="dropdown-backdrop"/>').insertBefore(e(this)).on("click",r),s.toggleClass("open")),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f<s.length-1&&f++,~f||(f=0),s.eq(f).focus()}};var s=e.fn.dropdown;e.fn.dropdown=function(t){return this.each(function(){var r=e(this),i=r.data("dropdown");i||r.data("dropdown",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.dropdown.Constructor=n,e.fn.dropdown.noConflict=function(){return e.fn.dropdown=s,this},e(document).on("click.dropdown.data-api",r).on("click.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("click.dropdown.data-api",t,n.prototype.toggle).on("keydown.dropdown.data-api",t+", [role=menu]",n.prototype.keydown)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=n,this.$element=e(t).delegate('[data-dismiss="modal"]',"click.dismiss.modal",e.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};t.prototype={constructor:t,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var t=this,n=e.Event("show");this.$element.trigger(n);if(this.isShown||n.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var n=e.support.transition&&t.$element.hasClass("fade");t.$element.parent().length||t.$element.appendTo(document.body),t.$element.show(),n&&t.$element[0].offsetWidth,t.$element.addClass("in").attr("aria-hidden",!1),t.enforceFocus(),n?t.$element.one(e.support.transition.end,function(){t.$element.focus().trigger("shown")}):t.$element.focus().trigger("shown")})},hide:function(t){t&&t.preventDefault();var n=this;t=e.Event("hide"),this.$element.trigger(t);if(!this.isShown||t.isDefaultPrevented())return;this.isShown=!1,this.escape(),e(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),e.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var t=this;e(document).on("focusin.modal",function(e){t.$element[0]!==e.target&&!t.$element.has(e.target).length&&t.$element.focus()})},escape:function(){var e=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(t){t.which==27&&e.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var t=this,n=setTimeout(function(){t.$element.off(e.support.transition.end),t.hideModal()},500);this.$element.one(e.support.transition.end,function(){clearTimeout(n),t.hideModal()})},hideModal:function(){var e=this;this.$element.hide(),this.backdrop(function(){e.removeBackdrop(),e.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(t){var n=this,r=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var i=e.support.transition&&r;this.$backdrop=e('<div class="modal-backdrop '+r+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e.fn[this.type].defaults,r={},i;this._options&&e.each(this._options,function(e,t){n[e]!=t&&(r[e]=t)},this),i=e(t.currentTarget)[this.type](r).data(this.type);if(!i.options.delay||!i.options.delay.show)return i.show();clearTimeout(this.timeout),i.hoverState="in",this.timeout=setTimeout(function(){i.hoverState=="in"&&i.show()},i.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(n=e.isFunction(this.source)?this.source(this.query,e.proxy(this.process,this)):this.source,n?this.process(n):this)},process:function(t){var n=this;return t=e.grep(t,function(e){return n.matcher(e)}),t=this.sorter(t),t.length?this.render(t.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return"<strong>"+t+"</strong>"})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery);
src/config/feature-admin_access_restriction.txt ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'admin_access_restriction'
3
+ properties:
4
+ name: 'Admin Access Restriction'
5
+ show_feature_menu_item: true
6
+ storage_key: 'admin_access_restriction' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_enable_plugin_feature_admin_access_restriction'
11
+ primary: true
12
+ -
13
+ slug: 'section_admin_access_restriction_settings'
14
+ primary: false
15
+ -
16
+ slug: 'section_non_ui'
17
+ hidden: true
18
+
19
+ # Define Options
20
+ options:
21
+ -
22
+ key: 'enable_admin_access_restriction'
23
+ section: 'section_enable_plugin_feature_admin_access_restriction'
24
+ default: 'N'
25
+ type: 'checkbox'
26
+ link_info: 'http://icwp.io/40'
27
+ link_blog: 'http://icwp.io/wpsf02'
28
+ -
29
+ key: 'admin_access_key'
30
+ section: 'section_admin_access_restriction_settings'
31
+ default: ''
32
+ type: 'password'
33
+ link_info: 'http://icwp.io/42'
34
+ link_blog: ''
35
+ -
36
+ key: 'admin_access_timeout'
37
+ section: 'section_admin_access_restriction_settings'
38
+ default: 30
39
+ type: 'integer'
40
+ link_info: 'http://icwp.io/41'
41
+ link_blog: ''
42
+ -
43
+ key: 'current_plugin_version'
44
+ section: 'section_non_ui'
45
+ -
46
+ key: 'admin_access_key_cookie_name'
47
+ section: 'section_non_ui'
48
+ value: 'icwp_wpsf_aakcook'
src/config/feature-audit_trail.txt ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'audit_trail'
3
+ properties:
4
+ name: 'Audit Trail'
5
+ show_feature_menu_item: true
6
+ storage_key: 'audit_trail' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_enable_plugin_feature_audit_trail'
11
+ primary: true
12
+ -
13
+ slug: 'section_enable_audit_contexts'
14
+ -
15
+ slug: 'section_non_ui'
16
+ hidden: true
17
+
18
+ # Define Options and assign to section slug
19
+ options:
20
+ -
21
+ key: 'enable_audit_trail'
22
+ section: 'section_enable_plugin_feature_audit_trail'
23
+ default: 'N'
24
+ type: 'checkbox'
25
+ link_info: ''
26
+ link_blog: ''
27
+ -
28
+ key: 'enable_audit_context_users'
29
+ section: 'section_enable_audit_contexts'
30
+ default: 'Y'
31
+ type: 'checkbox'
32
+ link_info: ''
33
+ link_blog: ''
34
+ -
35
+ key: 'enable_audit_context_plugins'
36
+ section: 'section_enable_audit_contexts'
37
+ default: 'Y'
38
+ type: 'checkbox'
39
+ link_info: ''
40
+ link_blog: ''
41
+ -
42
+ key: 'enable_audit_context_themes'
43
+ section: 'section_enable_audit_contexts'
44
+ default: 'Y'
45
+ type: 'checkbox'
46
+ link_info: ''
47
+ link_blog: ''
48
+ -
49
+ key: 'enable_audit_context_posts'
50
+ section: 'section_enable_audit_contexts'
51
+ default: 'Y'
52
+ type: 'checkbox'
53
+ link_info: ''
54
+ link_blog: ''
55
+ -
56
+ key: 'enable_audit_context_wordpress'
57
+ section: 'section_enable_audit_contexts'
58
+ default: 'Y'
59
+ type: 'checkbox'
60
+ link_info: ''
61
+ link_blog: ''
62
+ -
63
+ key: 'enable_audit_context_wpsf'
64
+ section: 'section_enable_audit_contexts'
65
+ default: 'Y'
66
+ type: 'checkbox'
67
+ link_info: ''
68
+ link_blog: ''
69
+ -
70
+ key: 'current_plugin_version'
71
+ section: 'section_non_ui'
72
+ -
73
+ key: 'audit_trail_table_name'
74
+ section: 'section_non_ui'
75
+ value: 'audit_trail'
src/config/feature-autoupdates.txt ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'autoupdates'
3
+ properties:
4
+ name: 'Automatic Updates'
5
+ show_feature_menu_item: true
6
+ storage_key: 'autoupdates' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_enable_plugin_feature_automatic_updates_control'
11
+ primary: true
12
+ -
13
+ slug: 'section_disable_all_wordpress_automatic_updates'
14
+ -
15
+ slug: 'section_automatic_plugin_self_update'
16
+ -
17
+ slug: 'section_automatic_updates_for_wordpress_components'
18
+ -
19
+ slug: 'section_automatic_update_email_notifications'
20
+ -
21
+ slug: 'section_non_ui'
22
+ hidden: true
23
+
24
+ # Define Options and assign to section slug
25
+ options:
26
+ -
27
+ key: 'enable_autoupdates'
28
+ section: 'section_enable_plugin_feature_automatic_updates_control'
29
+ default: 'Y'
30
+ type: 'checkbox'
31
+ link_info: 'http://icwp.io/3w'
32
+ link_blog: ''
33
+ -
34
+ key: 'enable_autoupdate_disable_all'
35
+ section: 'section_disable_all_wordpress_automatic_updates'
36
+ default: 'N'
37
+ type: 'checkbox'
38
+ link_info: 'http://icwp.io/3v'
39
+ link_blog: ''
40
+ -
41
+ key: 'autoupdate_plugin_self'
42
+ section: 'section_automatic_plugin_self_update'
43
+ default: 'Y'
44
+ type: 'checkbox'
45
+ link_info: 'http://icwp.io/3u'
46
+ link_blog: ''
47
+ -
48
+ key: 'autoupdate_core'
49
+ section: 'section_automatic_updates_for_wordpress_components'
50
+ default: 'core_minor'
51
+ type: 'select'
52
+ value_options:
53
+ -
54
+ value_key: 'core_never'
55
+ text: 'Never'
56
+ -
57
+ value_key: 'core_minor'
58
+ text: 'Minor Versions Only'
59
+ -
60
+ value_key: 'core_major'
61
+ text: 'Major and Minor Versions'
62
+ link_info: 'http://icwp.io/3x'
63
+ link_blog: ''
64
+ -
65
+ key: 'enable_autoupdate_plugins'
66
+ section: 'section_automatic_updates_for_wordpress_components'
67
+ default: 'N'
68
+ type: 'checkbox'
69
+ link_info: ''
70
+ link_blog: ''
71
+ -
72
+ key: 'enable_autoupdate_themes'
73
+ section: 'section_automatic_updates_for_wordpress_components'
74
+ default: 'N'
75
+ type: 'checkbox'
76
+ link_info: ''
77
+ link_blog: ''
78
+ -
79
+ key: 'enable_autoupdate_translations'
80
+ section: 'section_automatic_updates_for_wordpress_components'
81
+ default: 'Y'
82
+ type: 'checkbox'
83
+ link_info: ''
84
+ link_blog: ''
85
+ -
86
+ key: 'enable_autoupdate_ignore_vcs'
87
+ section: 'section_automatic_updates_for_wordpress_components'
88
+ default: 'N'
89
+ type: 'checkbox'
90
+ link_info: ''
91
+ link_blog: ''
92
+ -
93
+ key: 'enable_upgrade_notification_email'
94
+ section: 'section_automatic_update_email_notifications'
95
+ default: ''
96
+ type: 'checkbox'
97
+ link_info: ''
98
+ link_blog: ''
99
+ -
100
+ key: 'override_email_address'
101
+ section: 'section_automatic_update_email_notifications'
102
+ default: ''
103
+ type: 'email'
104
+ link_info: ''
105
+ link_blog: ''
106
+ -
107
+ key: 'current_plugin_version'
108
+ section: 'section_non_ui'
src/config/feature-comments_filter.txt ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'comments_filter'
3
+ properties:
4
+ name: 'Comments Filter'
5
+ show_feature_menu_item: true
6
+ storage_key: 'commentsfilter' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_enable_plugin_feature_spam_comments_protection_filter'
11
+ primary: true
12
+ -
13
+ slug: 'section_enable_human_comment_spam_protection_filter'
14
+ -
15
+ slug: 'section_enable_automatic_bot_comment_spam_protection_filter'
16
+ -
17
+ slug: 'section_customize_messages_shown_to_user'
18
+ -
19
+ slug: 'section_non_ui'
20
+ hidden: true
21
+
22
+ # Define Options and assign to section slug
23
+ options:
24
+ -
25
+ key: 'enable_comments_filter'
26
+ section: 'section_enable_plugin_feature_spam_comments_protection_filter'
27
+ default: 'N'
28
+ type: 'checkbox'
29
+ link_info: 'http://icwp.io/3z'
30
+ link_blog: 'http://icwp.io/wpsf04'
31
+ -
32
+ key: 'enable_comments_human_spam_filter'
33
+ section: 'section_enable_human_comment_spam_protection_filter'
34
+ default: 'N'
35
+ type: 'checkbox'
36
+ link_info: 'http://icwp.io/57'
37
+ link_blog: ''
38
+ -
39
+ key: 'enable_comments_human_spam_filter_items'
40
+ section: 'section_enable_human_comment_spam_protection_filter'
41
+ type: 'multiple_select'
42
+ default:
43
+ - 'author_name'
44
+ - 'author_email'
45
+ - 'comment_content'
46
+ - 'url'
47
+ - 'ip_address'
48
+ - 'user_agent'
49
+ value_options:
50
+ -
51
+ value_key: 'author_name'
52
+ text: 'Author Name'
53
+ -
54
+ value_key: 'author_email'
55
+ text: 'Author Email'
56
+ -
57
+ value_key: 'comment_content'
58
+ text: 'Comment Content'
59
+ -
60
+ value_key: 'url'
61
+ text: 'URL'
62
+ -
63
+ value_key: 'ip_address'
64
+ text: 'IP Address'
65
+ -
66
+ value_key: 'user_agent'
67
+ text: 'Browser User Agent'
68
+
69
+ link_info: 'http://icwp.io/58'
70
+ link_blog: ''
71
+ -
72
+ key: 'comments_default_action_human_spam'
73
+ section: 'section_enable_human_comment_spam_protection_filter'
74
+ default: 'spam'
75
+ type: 'select'
76
+ value_options:
77
+ -
78
+ value_key: 0
79
+ text: 'Mark As Pending Moderation'
80
+ -
81
+ value_key: 'spam'
82
+ text: 'Mark As SPAM'
83
+ -
84
+ value_key: 'trash'
85
+ text: 'Move To Trash'
86
+ -
87
+ value_key: 'reject'
88
+ text: 'Reject And Redirect'
89
+ -
90
+ key: 'enable_comments_gasp_protection'
91
+ section: 'section_enable_automatic_bot_comment_spam_protection_filter'
92
+ default: 'Y'
93
+ type: 'checkbox'
94
+ link_info: 'http://icwp.io/3n'
95
+ link_blog: 'http://icwp.io/2n'
96
+ -
97
+ key: 'enable_comments_gasp_protection_for_logged_in'
98
+ section: 'section_enable_automatic_bot_comment_spam_protection_filter'
99
+ default: 'N'
100
+ type: 'checkbox'
101
+ link_info: ''
102
+ link_blog: ''
103
+ -
104
+ key: 'comments_default_action_spam_bot'
105
+ section: 'section_enable_automatic_bot_comment_spam_protection_filter'
106
+ default: 'trash'
107
+ type: 'select'
108
+ value_options:
109
+ -
110
+ value_key: 0
111
+ text: 'Mark As Pending Moderation'
112
+ -
113
+ value_key: 'spam'
114
+ text: 'Mark As SPAM'
115
+ -
116
+ value_key: 'trash'
117
+ text: 'Move To Trash'
118
+ -
119
+ value_key: 'reject'
120
+ text: 'Reject And Redirect'
121
+
122
+ link_info: 'http://icwp.io/3x'
123
+ link_blog: ''
124
+ -
125
+ key: 'comments_cooldown_interval'
126
+ section: 'section_enable_automatic_bot_comment_spam_protection_filter'
127
+ default: 30
128
+ type: 'integer'
129
+ link_info: 'http://icwp.io/3o'
130
+ link_blog: ''
131
+ -
132
+ key: 'comments_token_expire_interval'
133
+ section: 'section_enable_automatic_bot_comment_spam_protection_filter'
134
+ default: 600
135
+ type: 'integer'
136
+ link_info: 'http://icwp.io/3o'
137
+ link_blog: ''
138
+ -
139
+ key: 'custom_message_checkbox'
140
+ section: 'section_customize_messages_shown_to_user'
141
+ default: "I'm not a spammer"
142
+ type: 'text'
143
+ link_info: 'http://icwp.io/3p'
144
+ link_blog: ''
145
+ -
146
+ key: 'custom_message_alert'
147
+ section: 'section_customize_messages_shown_to_user'
148
+ default: "Please check the box to confirm you're not a spammer"
149
+ type: 'text'
150
+ link_info: 'http://icwp.io/3p'
151
+ link_blog: ''
152
+ -
153
+ key: 'custom_message_comment_wait'
154
+ section: 'section_customize_messages_shown_to_user'
155
+ default: "Please wait %s seconds before posting your comment"
156
+ type: 'text'
157
+ link_info: 'http://icwp.io/3p'
158
+ link_blog: ''
159
+ -
160
+ key: 'custom_message_comment_reload'
161
+ section: 'section_customize_messages_shown_to_user'
162
+ default: "Please reload this page to post a comment"
163
+ type: 'text'
164
+ link_info: 'http://icwp.io/3p'
165
+ link_blog: ''
166
+ -
167
+ key: 'current_plugin_version'
168
+ section: 'section_non_ui'
169
+ -
170
+ key: 'spambot_comments_filter_table_name'
171
+ section: 'section_non_ui'
172
+ value: 'spambot_comments_filter'
src/config/feature-email.txt ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'email'
3
+ properties:
4
+ name: 'Email'
5
+ show_feature_menu_item: false
6
+ storage_key: 'email' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_email_options'
11
+ primary: true
12
+ -
13
+ slug: 'section_non_ui'
14
+ hidden: true
15
+
16
+ # Define Options
17
+ options:
18
+ -
19
+ key: 'block_send_email_address'
20
+ section: 'section_email_options'
21
+ default: ''
22
+ type: 'email'
23
+ link_info: ''
24
+ link_blog: ''
25
+ -
26
+ key: 'send_email_throttle_limit'
27
+ section: 'section_email_options'
28
+ default: 10
29
+ type: 'integer'
30
+ link_info: ''
31
+ link_blog: ''
32
+ -
33
+ key: 'current_plugin_version'
34
+ section: 'section_non_ui'
src/config/feature-firewall.txt ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'firewall'
3
+ properties:
4
+ name: 'Firewall'
5
+ show_feature_menu_item: true
6
+ storage_key: 'firewall' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_enable_plugin_feature_wordpress_firewall'
11
+ primary: true
12
+ -
13
+ slug: 'section_firewall_blocking_options'
14
+ -
15
+ slug: 'section_choose_firewall_block_response'
16
+ -
17
+ slug: 'section_whitelist'
18
+ -
19
+ slug: 'section_blacklist'
20
+ -
21
+ slug: 'section_firewall_logging'
22
+ -
23
+ slug: 'section_non_ui'
24
+ hidden: true
25
+
26
+ # Define Options
27
+ options:
28
+ -
29
+ key: 'enable_firewall'
30
+ section: 'section_enable_plugin_feature_wordpress_firewall'
31
+ default: 'N'
32
+ type: 'checkbox'
33
+ link_info: 'http://icwp.io/43'
34
+ link_blog: 'http://icwp.io/wpsf01'
35
+ -
36
+ key: 'include_cookie_checks'
37
+ section: 'section_firewall_blocking_options'
38
+ default: 'N'
39
+ type: 'checkbox'
40
+ link_info: ''
41
+ link_blog: ''
42
+ -
43
+ key: 'block_dir_traversal'
44
+ section: 'section_firewall_blocking_options'
45
+ default: 'Y'
46
+ type: 'checkbox'
47
+ link_info: ''
48
+ link_blog: ''
49
+ -
50
+ key: 'block_sql_queries'
51
+ section: 'section_firewall_blocking_options'
52
+ default: 'Y'
53
+ type: 'checkbox'
54
+ link_info: ''
55
+ link_blog: ''
56
+ -
57
+ key: 'block_wordpress_terms'
58
+ section: 'section_firewall_blocking_options'
59
+ default: 'N'
60
+ type: 'checkbox'
61
+ link_info: ''
62
+ link_blog: ''
63
+ -
64
+ key: 'block_field_truncation'
65
+ section: 'section_firewall_blocking_options'
66
+ default: 'Y'
67
+ type: 'checkbox'
68
+ link_info: ''
69
+ link_blog: ''
70
+ -
71
+ key: 'block_php_code'
72
+ section: 'section_firewall_blocking_options'
73
+ default: 'N'
74
+ type: 'checkbox'
75
+ link_info: ''
76
+ link_blog: ''
77
+ -
78
+ key: 'block_exe_file_uploads'
79
+ section: 'section_firewall_blocking_options'
80
+ default: 'N'
81
+ type: 'checkbox'
82
+ link_info: ''
83
+ link_blog: ''
84
+ -
85
+ key: 'block_response'
86
+ section: 'section_choose_firewall_block_response'
87
+ default: 'redirect_die_message'
88
+ type: 'select'
89
+ value_options:
90
+ -
91
+ value_key: 'redirect_die_message'
92
+ text: 'Die With Message'
93
+ -
94
+ value_key: 'redirect_die'
95
+ text: 'Die'
96
+ -
97
+ value_key: 'redirect_home'
98
+ text: 'Redirect To Home Page'
99
+ -
100
+ value_key: 'redirect_404'
101
+ text: 'Return 404'
102
+ link_info: ''
103
+ link_blog: ''
104
+ -
105
+ key: 'block_send_email'
106
+ section: 'section_choose_firewall_block_response'
107
+ default: 'N'
108
+ type: 'checkbox'
109
+ link_info: ''
110
+ link_blog: ''
111
+ -
112
+ key: 'ips_whitelist'
113
+ section: 'section_whitelist'
114
+ default: ''
115
+ type: 'ip_addresses'
116
+ link_info: ''
117
+ link_blog: ''
118
+ -
119
+ key: 'page_params_whitelist'
120
+ section: 'section_whitelist'
121
+ default: ''
122
+ type: 'comma_separated_lists'
123
+ link_info: 'http://icwp.io/2a'
124
+ link_blog: ''
125
+ -
126
+ key: 'whitelist_admins'
127
+ section: 'section_whitelist'
128
+ default: 'N'
129
+ type: 'checkbox'
130
+ link_info: ''
131
+ link_blog: ''
132
+ -
133
+ key: 'ignore_search_engines'
134
+ section: 'section_whitelist'
135
+ default: 'N'
136
+ type: 'checkbox'
137
+ link_info: ''
138
+ link_blog: ''
139
+ -
140
+ key: 'ips_blacklist'
141
+ section: 'section_blacklist'
142
+ default: ''
143
+ type: 'ip_addresses'
144
+ link_info: ''
145
+ link_blog: ''
146
+ -
147
+ key: 'enable_firewall_log'
148
+ section: 'section_firewall_logging'
149
+ default: 'N'
150
+ type: 'checkbox'
151
+ link_info: ''
152
+ link_blog: ''
153
+ -
154
+ key: 'current_plugin_version'
155
+ section: 'section_non_ui'
src/config/feature-lockdown.txt ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'lockdown'
3
+ properties:
4
+ name: 'Lockdown'
5
+ show_feature_menu_item: true
6
+ storage_key: 'lockdown' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_enable_plugin_feature_wordpress_lockdown'
11
+ primary: true
12
+ -
13
+ slug: 'section_permission_access_options'
14
+ -
15
+ slug: 'section_wordpress_obscurity_options'
16
+ -
17
+ slug: 'section_non_ui'
18
+ hidden: true
19
+
20
+ # Define Options
21
+ options:
22
+ -
23
+ key: 'enable_lockdown'
24
+ section: 'section_enable_plugin_feature_wordpress_lockdown'
25
+ default: 'N'
26
+ type: 'checkbox'
27
+ link_info: 'http://icwp.io/4r'
28
+ link_blog: ''
29
+ -
30
+ key: 'disable_file_editing'
31
+ section: 'section_permission_access_options'
32
+ default: 'N'
33
+ type: 'checkbox'
34
+ link_info: 'http://icwp.io/4q'
35
+ link_blog: ''
36
+ -
37
+ key: 'force_ssl_login'
38
+ section: 'section_permission_access_options'
39
+ default: 'N'
40
+ type: 'checkbox'
41
+ link_info: 'http://icwp.io/4s'
42
+ link_blog: ''
43
+ -
44
+ key: 'force_ssl_admin'
45
+ section: 'section_permission_access_options'
46
+ default: 'N'
47
+ type: 'checkbox'
48
+ link_info: 'http://icwp.io/4t'
49
+ link_blog: ''
50
+ -
51
+ key: 'mask_wordpress_version'
52
+ section: 'section_wordpress_obscurity_options'
53
+ default: ''
54
+ type: 'text'
55
+ link_info: 'http://icwp.io/43'
56
+ link_blog: ''
57
+ -
58
+ key: 'hide_wordpress_generator_tag'
59
+ section: 'section_wordpress_obscurity_options'
60
+ default: 'N'
61
+ type: 'checkbox'
62
+ link_info: ''
63
+ link_blog: ''
64
+ -
65
+ key: 'current_plugin_version'
66
+ section: 'section_non_ui'
src/config/feature-logging.txt ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'logging'
3
+ properties:
4
+ name: 'Logging'
5
+ show_feature_menu_item: false
6
+ storage_key: 'logging' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_non_ui'
11
+ hidden: true
12
+
13
+ # Define Options
14
+ options:
15
+ -
16
+ key: 'enable_logging'
17
+ section: 'section_non_ui'
18
+ type: 'boolean'
19
+ default: true
20
+ -
21
+ key: 'general_logging_table_name'
22
+ section: 'section_non_ui'
23
+ type: 'text'
24
+ value: 'general_logging'
25
+ -
26
+ key: 'current_plugin_version'
27
+ section: 'section_non_ui'
src/config/feature-login_protect.txt ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'login_protect'
3
+ properties:
4
+ name: 'Login Protection'
5
+ show_feature_menu_item: true
6
+ storage_key: 'loginprotect' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_enable_plugin_feature_login_protection'
11
+ primary: true
12
+ -
13
+ slug: 'section_bypass_login_protection'
14
+ -
15
+ slug: 'section_two_factor_authentication'
16
+ -
17
+ slug: 'section_brute_force_login_protection'
18
+ -
19
+ slug: 'section_yubikey_authentication'
20
+ -
21
+ slug: 'section_login_logging'
22
+ -
23
+ slug: 'section_non_ui'
24
+ hidden: true
25
+
26
+ # Define Options
27
+ options:
28
+ -
29
+ key: 'enable_login_protect'
30
+ section: 'section_enable_plugin_feature_login_protection'
31
+ default: 'N'
32
+ type: 'checkbox'
33
+ link_info: 'http://icwp.io/51'
34
+ link_blog: 'http://icwp.io/wpsf03'
35
+ -
36
+ key: 'enable_xmlrpc_compatibility'
37
+ section: 'section_bypass_login_protection'
38
+ default: 'Y'
39
+ type: 'checkbox'
40
+ link_info: ''
41
+ link_blog: ''
42
+ -
43
+ key: 'ips_whitelist'
44
+ section: 'section_bypass_login_protection'
45
+ default: ''
46
+ type: 'ip_addresses'
47
+ link_info: 'http://icwp.io/52'
48
+ link_blog: ''
49
+ -
50
+ key: 'two_factor_auth_user_roles'
51
+ section: 'section_two_factor_authentication'
52
+ type: 'multiple_select'
53
+ default:
54
+ - 1
55
+ - 2
56
+ - 3
57
+ - 8
58
+ value_options:
59
+ -
60
+ value_key: 0
61
+ text: 'Subscribers'
62
+ -
63
+ value_key: 1
64
+ text: 'Contributors'
65
+ -
66
+ value_key: 2
67
+ text: 'Authors'
68
+ -
69
+ value_key: 3
70
+ text: 'Editors'
71
+ -
72
+ value_key: 8
73
+ text: 'Administrators'
74
+ link_info: 'http://icwp.io/4v'
75
+ link_blog: ''
76
+ -
77
+ key: 'enable_two_factor_auth_by_ip'
78
+ section: 'section_two_factor_authentication'
79
+ default: 'N'
80
+ type: 'checkbox'
81
+ link_info: 'http://icwp.io/3s'
82
+ link_blog: ''
83
+ -
84
+ key: 'enable_two_factor_auth_by_cookie'
85
+ section: 'section_two_factor_authentication'
86
+ default: 'N'
87
+ type: 'checkbox'
88
+ link_info: 'http://icwp.io/3t'
89
+ link_blog: ''
90
+ -
91
+ key: 'enable_two_factor_bypass_on_email_fail'
92
+ section: 'section_two_factor_authentication'
93
+ default: 'N'
94
+ type: 'checkbox'
95
+ link_info: ''
96
+ link_blog: ''
97
+ -
98
+ key: 'login_limit_interval'
99
+ section: 'section_brute_force_login_protection'
100
+ default: '10'
101
+ type: 'integer'
102
+ link_info: 'http://icwp.io/3q'
103
+ link_blog: ''
104
+ -
105
+ key: 'enable_login_gasp_check'
106
+ section: 'section_brute_force_login_protection'
107
+ default: 'Y'
108
+ type: 'checkbox'
109
+ link_info: 'http://icwp.io/3r'
110
+ link_blog: ''
111
+ -
112
+ key: 'enable_prevent_remote_post'
113
+ section: 'section_brute_force_login_protection'
114
+ default: 'Y'
115
+ type: 'checkbox'
116
+ link_info: 'http://icwp.io/4n'
117
+ link_blog: ''
118
+ -
119
+ key: 'enable_yubikey'
120
+ section: 'section_yubikey_authentication'
121
+ default: 'N'
122
+ type: 'checkbox'
123
+ link_info: 'http://icwp.io/4f'
124
+ link_blog: ''
125
+ -
126
+ key: 'yubikey_app_id'
127
+ section: 'section_yubikey_authentication'
128
+ default: ''
129
+ type: 'text'
130
+ link_info: 'http://icwp.io/4g'
131
+ link_blog: ''
132
+ -
133
+ key: 'yubikey_api_key'
134
+ section: 'section_yubikey_authentication'
135
+ default: ''
136
+ type: 'text'
137
+ link_info: 'http://icwp.io/4g'
138
+ link_blog: ''
139
+ -
140
+ key: 'yubikey_unique_keys'
141
+ section: 'section_yubikey_authentication'
142
+ default: ''
143
+ type: 'yubikey_unique_keys'
144
+ link_info: 'http://icwp.io/4h'
145
+ link_blog: ''
146
+ -
147
+ key: 'enable_login_protect_log'
148
+ section: 'section_login_logging'
149
+ hidden: true
150
+ default: 'N'
151
+ type: 'checkbox'
152
+ link_info: 'http://icwp.io/4h'
153
+ link_blog: ''
154
+ -
155
+ key: 'current_plugin_version'
156
+ section: 'section_non_ui'
157
+ -
158
+ key: 'gasp_key'
159
+ section: 'section_non_ui'
160
+ -
161
+ key: 'two_factor_secret_key'
162
+ section: 'section_non_ui'
163
+ -
164
+ key: 'last_login_time'
165
+ section: 'section_non_ui'
166
+ -
167
+ key: 'last_login_time_file_path'
168
+ section: 'section_non_ui'
169
+ -
170
+ key: 'log_category'
171
+ section: 'section_non_ui'
172
+ -
173
+ key: 'two_factor_auth_table_name'
174
+ section: 'section_non_ui'
175
+ value: 'login_auth'
176
+ -
177
+ key: 'two_factor_auth_cookie_name'
178
+ section: 'section_non_ui'
179
+ value: 'wpsf_auth'
180
+ -
181
+ key: 'two_factor_auth_table_created'
182
+ section: 'section_non_ui'
src/config/feature-plugin.txt ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'plugin'
3
+ properties:
4
+ name: 'Dashboard'
5
+ show_feature_menu_item: true
6
+ storage_key: 'plugin' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_general_plugin_options'
11
+ primary: true
12
+ -
13
+ slug: 'section_non_ui'
14
+ hidden: true
15
+
16
+ # Define Options
17
+ options:
18
+ -
19
+ key: 'block_send_email_address'
20
+ section: 'section_general_plugin_options'
21
+ default: ''
22
+ type: 'email'
23
+ link_info: ''
24
+ link_blog: ''
25
+ -
26
+ key: 'enable_upgrade_admin_notice'
27
+ section: 'section_general_plugin_options'
28
+ default: 'Y'
29
+ type: 'checkbox'
30
+ link_info: ''
31
+ link_blog: ''
32
+ -
33
+ key: 'delete_on_deactivate'
34
+ section: 'section_general_plugin_options'
35
+ default: 'N'
36
+ type: 'checkbox'
37
+ link_info: ''
38
+ link_blog: ''
39
+ -
40
+ key: 'current_plugin_version'
41
+ section: 'section_non_ui'
42
+ -
43
+ key: 'secret_key'
44
+ section: 'section_non_ui'
45
+ -
46
+ key: 'installation_time'
47
+ section: 'section_non_ui'
48
+ -
49
+ key: 'feedback_admin_notice'
50
+ section: 'section_non_ui'
51
+ -
52
+ key: 'update_success_tracker'
53
+ section: 'section_non_ui'
54
+ -
55
+ key: 'capability_can_disk_write'
56
+ section: 'section_non_ui'
57
+ -
58
+ key: 'capability_can_remote_get'
59
+ section: 'section_non_ui'
60
+ -
61
+ key: 'active_plugin_features'
62
+ section: 'section_non_ui'
63
+ value:
64
+ -
65
+ slug: 'admin_access_restriction'
66
+ storage_key: 'admin_access_restriction'
67
+ -
68
+ slug: 'firewall'
69
+ storage_key: 'firewall'
70
+ -
71
+ slug: 'login_protect'
72
+ storage_key: 'loginprotect'
73
+ -
74
+ slug: 'user_management'
75
+ storage_key: 'user_management'
76
+ -
77
+ slug: 'comments_filter'
78
+ storage_key: 'commentsfilter'
79
+ -
80
+ slug: 'autoupdates'
81
+ storage_key: 'autoupdates'
82
+ -
83
+ slug: 'lockdown'
84
+ storage_key: 'lockdown'
85
+ -
86
+ slug: 'audit_trail'
87
+ storage_key: 'audit_trail'
88
+ hidden: true
89
+ -
90
+ slug: 'email'
91
+ storage_key: 'email'
92
+ -
93
+ slug: 'logging'
94
+ storage_key: 'logging'
src/config/feature-user_management.txt ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ slug: 'user_management'
3
+ properties:
4
+ name: 'User Management'
5
+ show_feature_menu_item: true
6
+ storage_key: 'user_management' # should correspond exactly to that in the plugin.yaml
7
+ # Options Sections
8
+ sections:
9
+ -
10
+ slug: 'section_enable_plugin_feature_user_accounts_management'
11
+ primary: true
12
+ -
13
+ slug: 'section_bypass_user_accounts_management'
14
+ -
15
+ slug: 'section_admin_login_notification'
16
+ -
17
+ slug: 'section_user_session_management'
18
+ -
19
+ slug: 'section_non_ui'
20
+ hidden: true
21
+
22
+ # Define Options
23
+ options:
24
+ -
25
+ key: 'enable_user_management'
26
+ section: 'section_enable_plugin_feature_user_accounts_management'
27
+ default: 'N'
28
+ type: 'checkbox'
29
+ link_info: ''
30
+ link_blog: ''
31
+ -
32
+ key: 'enable_xmlrpc_compatibility'
33
+ section: 'section_bypass_user_accounts_management'
34
+ default: 'Y'
35
+ type: 'checkbox'
36
+ link_info: ''
37
+ link_blog: ''
38
+ -
39
+ key: 'enable_admin_login_email_notification'
40
+ section: 'section_admin_login_notification'
41
+ default: ''
42
+ type: 'email'
43
+ link_info: 'http://icwp.io/3u'
44
+ link_blog: ''
45
+ -
46
+ key: 'session_timeout_interval'
47
+ section: 'section_user_session_management'
48
+ default: '2'
49
+ type: 'integer'
50
+ link_info: 'http://icwp.io/3x'
51
+ link_blog: ''
52
+ -
53
+ key: 'session_idle_timeout_interval'
54
+ section: 'section_user_session_management'
55
+ default: '0'
56
+ type: 'integer'
57
+ link_info: ''
58
+ link_blog: ''
59
+ -
60
+ key: 'session_lock_location'
61
+ section: 'section_user_session_management'
62
+ default: 'N'
63
+ type: 'checkbox'
64
+ link_info: ''
65
+ link_blog: ''
66
+ -
67
+ key: 'session_username_concurrent_limit'
68
+ section: 'section_user_session_management'
69
+ default: '0'
70
+ type: 'integer'
71
+ link_info: ''
72
+ link_blog: ''
73
+ -
74
+ key: 'session_check_admin_area_only'
75
+ hidden: true
76
+ section: 'section_user_session_management'
77
+ default: 'Y'
78
+ type: 'checkbox'
79
+ link_info: ''
80
+ link_blog: ''
81
+ -
82
+ key: 'session_auto_forward_to_admin_area'
83
+ hidden: true
84
+ section: 'section_user_session_management'
85
+ default: 'Y'
86
+ type: 'checkbox'
87
+ link_info: ''
88
+ link_blog: ''
89
+ -
90
+ key: 'current_plugin_version'
91
+ section: 'section_non_ui'
92
+ -
93
+ key: 'user_sessions_table_name'
94
+ section: 'section_non_ui'
95
+ value: 'user_management'
96
+ -
97
+ key: 'user_session_cookie_name'
98
+ section: 'section_non_ui'
99
+ value: 'wpsf_sesh_id'
100
+ -
101
+ key: 'user_management_table_created'
102
+ section: 'section_non_ui'
src/icwp-base-processor.php DELETED
@@ -1,384 +0,0 @@
1
- <?php
2
- /**
3
- * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
- * All rights reserved.
5
- *
6
- * Version: 2013-08-27-B
7
- *
8
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
9
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
12
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
14
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
15
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
16
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
17
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
- *
19
- */
20
-
21
- if ( !class_exists('ICWP_BaseProcessor_V3') ):
22
-
23
- class ICWP_BaseProcessor_V3 {
24
-
25
- const PcreDelimiter = '/';
26
- const LOG_MESSAGE_LEVEL_INFO = 0;
27
- const LOG_MESSAGE_LEVEL_WARNING = 1;
28
- const LOG_MESSAGE_LEVEL_CRITICAL = 2;
29
-
30
- const LOG_CATEGORY_DEFAULT = 0;
31
- const LOG_CATEGORY_FIREWALL = 1;
32
- const LOG_CATEGORY_LOGINPROTECT = 2;
33
-
34
- /**
35
- * @var array
36
- */
37
- protected $m_aLog;
38
- /**
39
- * @var array
40
- */
41
- protected $m_aLogMessages;
42
-
43
- /**
44
- * @var long
45
- */
46
- protected static $nRequestIp;
47
- /**
48
- * @var long
49
- */
50
- protected static $nRequestPostId;
51
- /**
52
- * @var integer
53
- */
54
- protected static $nRequestTimestamp;
55
-
56
- /**
57
- * @var array
58
- */
59
- protected $aOptions;
60
-
61
- /**
62
- * @var ICWP_WPSF_FeatureHandler_Base
63
- */
64
- protected $oFeatureOptions;
65
-
66
- public function __construct( ICWP_WPSF_FeatureHandler_Base $oFeatureOptions ) {
67
- $this->oFeatureOptions = $oFeatureOptions;
68
- $this->reset();
69
- }
70
-
71
- /**
72
- * Resets the object values to be re-used anew
73
- */
74
- public function reset() {
75
- if ( !isset( self::$nRequestIp ) ) {
76
- self::$nRequestIp = $this->getVisitorIpAddress();
77
- }
78
- if ( !isset( self::$nRequestTimestamp ) ) {
79
- self::$nRequestTimestamp = time();
80
- }
81
- $this->resetLog();
82
- }
83
-
84
- /**
85
- * Override to set what this processor does when it's "run"
86
- */
87
- public function run() { }
88
-
89
- /**
90
- */
91
- public function deleteStore() {
92
- delete_option( $this->constructStorageKey() );
93
- }
94
-
95
- /**
96
- *
97
- * @param array $aOptions
98
- */
99
- public function setOptions( &$aOptions ) {
100
- $this->aOptions = $aOptions;
101
- }
102
-
103
- /**
104
- * @param $sOptionKey
105
- * @param bool $mDefault
106
- * @return bool
107
- */
108
- public function getOption( $sOptionKey, $mDefault = false ) {
109
- if ( !isset( $this->aOptions ) ) {
110
- $this->aOptions = $this->oFeatureOptions->getPluginOptionsValues();
111
- }
112
- return isset( $this->aOptions[$sOptionKey] )? $this->aOptions[$sOptionKey] : $mDefault;
113
- }
114
-
115
- /**
116
- * @param $sKey
117
- * @param mixed $mValueToTest
118
- * @param boolean $fStrict
119
- * @return bool
120
- */
121
- public function getIsOption( $sKey, $mValueToTest, $fStrict = false ) {
122
- $mOptionValue = $this->getOption($sKey);
123
- return $fStrict? $mOptionValue === $mValueToTest : $mOptionValue == $mValueToTest;
124
- }
125
-
126
- /**
127
- * @return bool|long
128
- */
129
- public function getRequestPostId() {
130
- if ( !isset( self::$nRequestPostId ) ) {
131
- global $post;
132
- if ( empty( $post ) ) {
133
- return false;
134
- }
135
- self::$nRequestPostId = $post->ID;
136
- }
137
- return self::$nRequestPostId;
138
- }
139
-
140
- /**
141
- * Resets the log
142
- */
143
- public function resetLog() {
144
- $this->m_aLogMessages = array();
145
- }
146
-
147
- /**
148
- * @return bool
149
- */
150
- public function getIsLogging() {
151
- return false;
152
- }
153
-
154
- /**
155
- * Should return false when logging is disabled.
156
- *
157
- * @return false|array - false when logging is disabled, array with log data otherwise
158
- * @see ICWP_WPSF_BaseProcessor::getLogData()
159
- */
160
- public function flushLogData() {
161
- if ( !$this->getIsLogging() ) {
162
- return false;
163
- }
164
- return false;
165
- }
166
-
167
- /**
168
- * Builds and returns the full log.
169
- *
170
- * @return array (associative)
171
- */
172
- public function getLogData() {
173
-
174
- if ( $this->getIsLogging() ) {
175
- $this->m_aLog = array( 'messages' => serialize( $this->m_aLogMessages ) );
176
- }
177
- else {
178
- $this->m_aLog = false;
179
- }
180
-
181
- return $this->m_aLog;
182
- }
183
-
184
- /**
185
- * @return array
186
- */
187
- public function getLogMessages() {
188
- if ( !is_array( $this->m_aLogMessages ) ) {
189
- $this->m_aLogMessages = array();
190
- }
191
- return $this->m_aLogMessages;
192
- }
193
-
194
- /**
195
- * @param string $sLogMessage
196
- * @param integer $sMessageType
197
- */
198
- public function writeLog( $sLogMessage = '', $sMessageType = self::LOG_MESSAGE_LEVEL_INFO ) {
199
- if ( !is_array( $this->m_aLogMessages ) ) {
200
- $this->resetLog();
201
- }
202
- $this->m_aLogMessages[] = array( $sMessageType, $sLogMessage );
203
- }
204
- /**
205
- * @param string $insLogMessage
206
- */
207
- public function logInfo( $insLogMessage ) {
208
- $this->writeLog( $insLogMessage, self::LOG_MESSAGE_LEVEL_INFO );
209
- }
210
- /**
211
- * @param string $insLogMessage
212
- */
213
- public function logWarning( $insLogMessage ) {
214
- $this->writeLog( $insLogMessage, self::LOG_MESSAGE_LEVEL_WARNING );
215
- }
216
- /**
217
- * @param string $insLogMessage
218
- */
219
- public function logCritical( $insLogMessage ) {
220
- $this->writeLog( $insLogMessage, self::LOG_MESSAGE_LEVEL_CRITICAL );
221
- }
222
-
223
- /**
224
- * @param boolean $infAsLong - visitor IP Address as IP2Long
225
- * @return integer - visitor IP Address as IP2Long
226
- */
227
- public function getVisitorIpAddress( $infAsLong = true ) {
228
- require_once( dirname(__FILE__).'/icwp-data-processor.php' );
229
- return ICWP_WPSF_DataProcessor::GetVisitorIpAddress( $infAsLong );
230
- }
231
-
232
- /**
233
- * @param array $inaIpList
234
- * @param integer $innIpAddress
235
- * @return boolean
236
- */
237
- public function isIpOnlist( $inaIpList, $innIpAddress = '', &$outsLabel = '' ) {
238
-
239
- if ( empty( $innIpAddress ) || !isset( $inaIpList['ips'] ) ) {
240
- return false;
241
- }
242
-
243
- $outsLabel = '';
244
- foreach( $inaIpList['ips'] as $mWhitelistAddress ) {
245
-
246
- $aIps = $this->parseIpAddress( $mWhitelistAddress );
247
- if ( count( $aIps ) === 1 ) { //not a range
248
- if ( $innIpAddress == $aIps[0] ) {
249
- $outsLabel = $inaIpList['meta'][ md5( $mWhitelistAddress ) ];
250
- return true;
251
- }
252
- }
253
- else if ( count( $aIps ) == 2 ) {
254
- if ( $aIps[0] <= $innIpAddress && $innIpAddress <= $aIps[1] ) {
255
- $outsLabel = $inaIpList['meta'][ md5( $mWhitelistAddress ) ];
256
- return true;
257
- }
258
- }
259
- }
260
- return false;
261
- }
262
-
263
- /**
264
- * @param string $insIpAddress - an IP or IP address range in LONG format.
265
- * @return array - with 1 ip address, or 2 addresses if it is a range.
266
- */
267
- protected function parseIpAddress( $insIpAddress ) {
268
-
269
- $aIps = array();
270
-
271
- if ( empty($insIpAddress) ) {
272
- return $aIps;
273
- }
274
-
275
- // offset=1 in the case that it's a range and the first number is negative on 32-bit systems
276
- $mPos = strpos( $insIpAddress, '-', 1 );
277
-
278
- if ( $mPos === false ) { //plain IP address
279
- $aIps[] = $insIpAddress;
280
- }
281
- else {
282
- //we remove the first character in case this is '-'
283
- $aParts = array( substr( $insIpAddress, 0, 1 ), substr( $insIpAddress, 1 ) );
284
- list( $sStart, $sEnd ) = explode( '-', $aParts[1], 2 );
285
- $aIps[] = $aParts[0].$sStart;
286
- $aIps[] = $sEnd;
287
- }
288
- return $aIps;
289
- }
290
-
291
- /**
292
- * @return ICWP_WPSF_EmailProcessor
293
- */
294
- public function getEmailProcessor() {
295
- return $this->oFeatureOptions->getEmailProcessor();
296
- }
297
-
298
- /**
299
- * @return ICWP_WPSF_LoggingProcessor
300
- */
301
- public function getLoggingProcessor() {
302
- return $this->oFeatureOptions->getLoggingProcessor();
303
- }
304
-
305
- /**
306
- * Checks the $inaData contains valid key values as laid out in $inaChecks
307
- *
308
- * @param array $aData
309
- * @param array $inaChecks
310
- * @return boolean
311
- */
312
- protected function validateParameters( $aData, $inaChecks ) {
313
-
314
- if ( !is_array( $aData ) ) {
315
- return false;
316
- }
317
-
318
- foreach( $inaChecks as $sCheck ) {
319
- if ( !array_key_exists( $sCheck, $aData ) || empty( $aData[ $sCheck ] ) ) {
320
- return false;
321
- }
322
- }
323
- return true;
324
- }
325
-
326
- /**
327
- * @return string
328
- */
329
- protected function constructStorageKey() {
330
- return sprintf( '%s%s_processor', $this->oFeatureOptions->getOptionStoragePrefix(), $this->oFeatureOptions->getFeatureSlug() );
331
- }
332
-
333
- /**
334
- * Override this to provide custom cleanup.
335
- */
336
- public function deleteAndCleanUp() {
337
- $this->deleteStore();
338
- }
339
-
340
- /**
341
- */
342
- protected function loadDataProcessor() {
343
- if ( !class_exists( 'ICWP_WPSF_DataProcessor' ) ) {
344
- require_once( dirname(__FILE__) . '/icwp-data-processor.php' );
345
- }
346
- }
347
-
348
- /**
349
- * @return ICWP_WpFilesystem_WPSF
350
- */
351
- protected function loadFileSystemProcessor() {
352
- require_once( dirname(__FILE__) . '/icwp-wpfilesystem.php' );
353
- return ICWP_WpFilesystem_WPSF::GetInstance();
354
- }
355
-
356
- /**
357
- * @return ICWP_WpFunctions_WPSF
358
- */
359
- protected function loadWpFunctionsProcessor() {
360
- require_once( dirname(__FILE__) . '/icwp-wpfunctions.php' );
361
- return ICWP_WpFunctions_WPSF::GetInstance();
362
- }
363
-
364
- /**
365
- * @return ICWP_Stats_WPSF
366
- */
367
- protected function loadWpsfStatsProcessor() {
368
- require_once( dirname(__FILE__) . '/icwp-wpsf-stats.php' );
369
- }
370
-
371
- /**
372
- * @param $sStatKey
373
- */
374
- protected function doStatIncrement( $sStatKey ) {
375
- $this->loadWpsfStatsProcessor();
376
- ICWP_Stats_WPSF::DoStatIncrement( $sStatKey );
377
- }
378
- }
379
-
380
- endif;
381
-
382
- if ( !class_exists('ICWP_WPSF_BaseProcessor') ):
383
- class ICWP_WPSF_BaseProcessor extends ICWP_BaseProcessor_V3 { }
384
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/icwp-data-processor.php CHANGED
@@ -3,8 +3,6 @@
3
  /**
4
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
5
  * All rights reserved.
6
- *
7
- * Version: 2013-08-27-A
8
  *
9
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
10
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -19,474 +17,549 @@
19
  *
20
  */
21
 
22
- if ( !class_exists('ICWP_DataProcessor_V1') ):
23
-
24
- class ICWP_DataProcessor_V1 {
25
-
26
- public static $fUseFilter = false;
27
-
28
- /**
29
- * @var string
30
- */
31
- protected static $sIpAddress;
32
-
33
- /**
34
- * Cloudflare compatible.
35
- *
36
- * @param boolean $infAsLong
37
- * @return bool|integer - visitor IP Address as IP2Long
38
- */
39
- public static function GetVisitorIpAddress( $infAsLong = true ) {
40
-
41
- if ( !empty( self::$sIpAddress ) ) {
42
- return $infAsLong? ip2long( self::$sIpAddress ) : self::$sIpAddress;
 
 
 
 
 
 
 
 
 
 
 
43
  }
44
 
45
- $aAddressSourceOptions = array(
46
- 'HTTP_CF_CONNECTING_IP',
47
- 'HTTP_CLIENT_IP',
48
- 'HTTP_X_FORWARDED_FOR',
49
- 'HTTP_X_FORWARDED',
50
- 'HTTP_FORWARDED',
51
- 'REMOTE_ADDR'
52
- );
53
- $fCanUseFilter = function_exists( 'filter_var' ) && defined( 'FILTER_FLAG_NO_PRIV_RANGE' ) && defined( 'FILTER_FLAG_IPV4' );
54
-
55
- foreach( $aAddressSourceOptions as $sOption ) {
56
- if ( empty( $_SERVER[ $sOption ] ) ) {
57
- continue;
58
- }
59
- $sIpAddressToTest = $_SERVER[ $sOption ];
60
-
61
- $aIpAddresses = explode( ',', $sIpAddressToTest ); //sometimes a comma-separated list is returned
62
- foreach( $aIpAddresses as $sIpAddress ) {
63
-
64
- if ( $fCanUseFilter && !self::IsAddressInPublicIpRange( $sIpAddress ) ) {
 
 
 
 
 
 
65
  continue;
66
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  else {
68
- self::$sIpAddress = $sIpAddress;
69
- return $infAsLong? ip2long( self::$sIpAddress ) : self::$sIpAddress;
70
  }
71
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  }
73
- return false;
74
- }
75
 
76
- /**
77
- * Assumes a valid IPv4 address is provided as we're only testing for a whether the IP is public or not.
78
- *
79
- * @param string $insIpAddress
80
- * @uses filter_var
81
- * @return boolean
82
- */
83
- public static function IsAddressInPublicIpRange( $insIpAddress ) {
84
- return filter_var( $insIpAddress, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE );
85
- }
86
-
87
- static public function ExtractIpAddresses( $insAddresses = '' ) {
88
-
89
- $aRawAddresses = array();
90
-
91
- if ( empty( $insAddresses ) ) {
92
- return $aRawAddresses;
93
  }
94
- $aRawList = array_map( 'trim', explode( "\n", $insAddresses ) );
95
 
96
- self::$fUseFilter = function_exists('filter_var') && defined( FILTER_VALIDATE_IP );
 
 
 
 
 
 
97
 
98
- foreach( $aRawList as $sKey => $sRawAddressLine ) {
99
-
100
- if ( empty( $sRawAddressLine ) ) {
101
- continue;
102
  }
103
-
104
- // Each line can have a Label which is the IP separated with a space.
105
- $aParts = explode( ' ', $sRawAddressLine, 2 );
106
- if ( count( $aParts ) == 1 ) {
107
- $aParts[] = '';
 
 
 
 
 
 
 
 
 
108
  }
109
- $aRawAddresses[ $aParts[0] ] = trim( $aParts[1] );
110
- }
111
- return self::Add_New_Raw_Ips( array(), $aRawAddresses );
112
- }
113
-
114
- static public function ExtractCommaSeparatedList( $insRawList = '' ) {
115
-
116
- $aRawList = array();
117
- if ( empty( $insRawList ) ) {
118
- return $aRawList;
119
  }
120
- // $aRawList = array_map( 'trim', explode( "\n", $insRawList ) );
121
- $aRawList = array_map( 'trim', preg_split( '/\r\n|\r|\n/', $insRawList ) );
122
- $aNewList = array();
123
- $fHadStar = false;
124
- foreach( $aRawList as $sKey => $sRawLine ) {
125
-
126
- if ( empty( $sRawLine ) ) {
127
- continue;
128
- }
129
- $sRawLine = str_replace( ' ', '', $sRawLine );
130
- $aParts = explode( ',', $sRawLine, 2 );
131
- // we only permit 1x line beginning with *
132
- if ( $aParts[0] == '*' ) {
133
- if ( $fHadStar ) {
 
 
 
 
134
  continue;
135
  }
136
- $fHadStar = true;
137
- }
138
- else {
139
- //If there's only 1 item on the line, we assume it to be a global
140
- // parameter rule
141
- if ( count( $aParts ) == 1 || empty( $aParts[1] ) ) { // there was no comma in this line in the first place
142
- array_unshift( $aParts, '*' );
 
143
  }
 
 
 
 
 
 
 
 
 
 
144
  }
145
-
146
- $aParams = empty( $aParts[1] )? array() : explode( ',', $aParts[1] );
147
- $aNewList[ $aParts[0] ] = $aParams;
148
  }
149
- return $aNewList;
150
- }
151
-
152
- /**
153
- * Given a list of new IPv4 address ($inaNewRawAddresses) it'll add them to the existing list
154
- * ($inaCurrent) where they're not already found
155
- *
156
- * @param array $inaCurrent - the list to which to add the new addresses
157
- * @param array $inaNewRawAddresses - the new IPv4 addresses
158
- * @param int $outnNewAdded - the count of newly added IPs
159
- * @return unknown|Ambigous <multitype:multitype: , string>
160
- */
161
- public static function Add_New_Raw_Ips( $inaCurrent, $inaNewRawAddresses, &$outnNewAdded = 0 ) {
162
-
163
- $outnNewAdded = 0;
164
-
165
- if ( empty( $inaNewRawAddresses ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  return $inaCurrent;
167
  }
168
-
169
- if ( !array_key_exists( 'ips', $inaCurrent ) ) {
170
- $inaCurrent['ips'] = array();
171
- }
172
- if ( !array_key_exists( 'meta', $inaCurrent ) ) {
173
- $inaCurrent['meta'] = array();
174
- }
175
 
176
- foreach( $inaNewRawAddresses as $sRawIpAddress => $sLabel ) {
177
- $mVerifiedIp = self::Verify_Ip( $sRawIpAddress );
178
- if ( $mVerifiedIp !== false && !in_array( $mVerifiedIp, $inaCurrent['ips'] ) ) {
179
- $inaCurrent['ips'][] = $mVerifiedIp;
180
- if ( empty($sLabel) ) {
181
- $sLabel = 'no label';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  }
183
- $inaCurrent['meta'][ md5( $mVerifiedIp ) ] = $sLabel;
184
- $outnNewAdded++;
185
  }
186
- }
187
- return $inaCurrent;
188
- }
189
-
190
- /**
191
- * @param array $inaCurrent
192
- * @param array $inaRawAddresses - should be a plain numerical array of IPv4 addresses
193
- * @return array:
194
- */
195
- public static function Remove_Raw_Ips( $inaCurrent, $inaRawAddresses ) {
196
- if ( empty( $inaRawAddresses ) ) {
197
  return $inaCurrent;
198
  }
199
-
200
- if ( !array_key_exists( 'ips', $inaCurrent ) ) {
201
- $inaCurrent['ips'] = array();
202
- }
203
- if ( !array_key_exists( 'meta', $inaCurrent ) ) {
204
- $inaCurrent['meta'] = array();
205
- }
206
-
207
- foreach( $inaRawAddresses as $sRawIpAddress ) {
208
- $mVerifiedIp = self::Verify_Ip( $sRawIpAddress );
209
- if ( $mVerifiedIp === false ) {
210
- continue;
211
  }
212
- $mKey = array_search( $mVerifiedIp, $inaCurrent['ips'] );
213
- if ( $mKey !== false ) {
214
- unset( $inaCurrent['ips'][$mKey] );
215
- unset( $inaCurrent['meta'][ md5( $mVerifiedIp ) ] );
216
  }
217
  }
218
- return $inaCurrent;
219
- }
220
-
221
- public static function Verify_Ip( $insIpAddress ) {
222
-
223
- $sAddress = self::Clean_Ip( $insIpAddress );
224
-
225
- // Now, determine if this is an IP range, or just a plain IP address.
226
- if ( strpos( $sAddress, '-' ) === false ) { //plain IP address
227
- return self::Verify_Ip_Address( $sAddress );
228
- }
229
- else {
230
- return self::Verify_Ip_Range( $sAddress );
231
  }
232
- }
233
 
234
- public static function Clean_Ip( $insRawAddress ) {
235
- $insRawAddress = preg_replace( '/[a-z\s]/i', '', $insRawAddress );
236
- $insRawAddress = str_replace( '.', 'PERIOD', $insRawAddress );
237
- $insRawAddress = str_replace( '-', 'HYPEN', $insRawAddress );
238
- $insRawAddress = preg_replace( '/[^a-z0-9]/i', '', $insRawAddress );
239
- $insRawAddress = str_replace( 'PERIOD', '.', $insRawAddress );
240
- $insRawAddress = str_replace( 'HYPEN', '-', $insRawAddress );
241
- return $insRawAddress;
242
- }
243
-
244
- public static function Verify_Ip_Address( $insIpAddress ) {
245
- if ( self::$fUseFilter ) {
246
- if ( filter_var( $insIpAddress, FILTER_VALIDATE_IP ) ) {
247
- return ip2long( $insIpAddress );
248
  }
 
 
 
 
 
249
  }
250
- else {
251
- if ( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/', $insIpAddress ) ) { //It's a valid IPv4 format, now check components
252
- $aParts = explode( '.', $insIpAddress );
253
- foreach ( $aParts as $sPart ) {
254
- $sPart = intval( $sPart );
255
- if ( $sPart < 0 || $sPart > 255 ) {
256
- return false;
257
- }
258
- }
259
- return ip2long( $insIpAddress );
260
- }
261
  }
262
- return false;
263
- }
264
 
265
- /**
266
- * Taken from http://www.phacks.net/detecting-search-engine-bot-and-web-spiders/
267
- */
268
- public static function IsSearchEngineBot() {
 
 
 
 
 
 
 
 
 
 
 
 
269
 
270
- if ( empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
 
 
 
 
 
 
 
 
 
 
271
  return false;
272
  }
273
- $sUserAgent = $_SERVER['HTTP_USER_AGENT'];
274
- $sBots = 'Googlebot|bingbot|Twitterbot|Baiduspider|ia_archiver|R6_FeedFetcher|NetcraftSurveyAgent'
275
- .'|Sogou web spider|Yahoo! Slurp|facebookexternalhit|PrintfulBot|msnbot|UnwindFetchor|urlresolver|Butterfly|TweetmemeBot';
276
-
277
- return ( preg_match( "/$sBots/", $sUserAgent ) > 0 );
278
- //
279
- // $aBots = array(
280
- // 'Googlebot',
281
- // 'bingbot',
282
- // 'Twitterbot',
283
- // 'Baiduspider',
284
- // 'ia_archiver',
285
- // 'R6_FeedFetcher',
286
- // 'NetcraftSurveyAgent',
287
- // 'Sogou web spider',
288
- // 'Yahoo! Slurp',
289
- // 'facebookexternalhit',
290
- // 'PrintfulBot',
291
- // 'msnbot',
292
- // 'UnwindFetchor',
293
- // 'urlresolver',
294
- // 'Butterfly',
295
- // 'TweetmemeBot'
296
- // );
297
- //
298
- // $aCrawlers = array(
299
- // 'Google' => 'Google',
300
- // 'msnbot' => 'MSN',
301
- // 'Rambler' => 'Rambler',
302
- // 'Yahoo' => 'Yahoo',
303
- // 'AbachoBOT' => 'AbachoBOT',
304
- // 'accoona' => 'Accoona',
305
- // 'AcoiRobot' => 'AcoiRobot',
306
- // 'ASPSeek' => 'ASPSeek',
307
- // 'CrocCrawler' => 'CrocCrawler',
308
- // 'Dumbot' => 'Dumbot',
309
- // 'FAST-WebCrawler' => 'FAST-WebCrawler',
310
- // 'GeonaBot' => 'GeonaBot',
311
- // 'Gigabot' => 'Gigabot',
312
- // 'Lycos' => 'Lycos spider',
313
- // 'MSRBOT' => 'MSRBOT',
314
- // 'Scooter' => 'Altavista robot',
315
- // 'AltaVista' => 'Altavista robot',
316
- // 'IDBot' => 'ID-Search Bot',
317
- // 'eStyle' => 'eStyle Bot',
318
- // 'Scrubby' => 'Scrubby robot'
319
- // );
320
-
321
- return array_key_exists( $sUserAgent, $aCrawlers );
322
- }
323
-
324
- /**
325
- * The only ranges currently accepted are a.b.c.d-f.g.h.j
326
- * @param string $insIpAddressRange
327
- * @return string|boolean
328
- */
329
- public static function Verify_Ip_Range( $insIpAddressRange ) {
330
-
331
- list( $sIpRangeStart, $sIpRangeEnd ) = explode( '-', $insIpAddressRange, 2 );
332
-
333
- if ( $sIpRangeStart == $sIpRangeEnd ) {
334
- return self::Verify_Ip_Address( $sIpRangeStart );
335
- }
336
- else if ( self::Verify_Ip_Address( $sIpRangeStart ) && self::Verify_Ip_Address( $sIpRangeEnd ) ) {
337
- $nStart = ip2long( $sIpRangeStart );
338
- $nEnd = ip2long( $sIpRangeEnd );
339
-
340
- // do our best to order it
341
- if (
342
- ( $nStart > 0 && $nEnd > 0 && $nStart > $nEnd )
343
- || ( $nStart < 0 && $nEnd < 0 && $nStart > $nEnd )
344
- ) {
345
- $nTemp = $nStart;
346
- $nStart = $nEnd;
347
- $nEnd = $nTemp;
348
  }
349
- return $nStart.'-'.$nEnd;
350
  }
351
- return false;
352
- }
353
 
354
- public static function CleanYubikeyUniqueKeys( $insRawKeys ) {
355
- $aKeys = explode( "\n", $insRawKeys );
356
- foreach( $aKeys as $nIndex => $sUsernameKey ) {
357
- if ( empty( $sUsernameKey ) ) {
358
- unset( $aKeys[$nIndex] );
359
- continue;
 
 
 
 
 
 
 
 
 
360
  }
361
- $aParts = array_map( 'trim', explode( ',', $sUsernameKey ) );
362
- if ( empty( $aParts[0] ) || empty( $aParts[1] ) || strlen( $aParts[1] ) < 12 ) {
363
- unset( $aKeys[$nIndex] );
364
- continue;
365
  }
366
- $aParts[1] = substr( $aParts[1], 0, 12 );
367
- $aKeys[$nIndex] = array( $aParts[0] => $aParts[1] );
368
  }
369
- return $aKeys;
370
- }
371
 
372
- /**
373
- * @param integer $innLength
374
- * @param boolean $infBeginLetter
375
- * @return string
376
- */
377
- static public function GenerateRandomString( $innLength = 10, $infBeginLetter = false ) {
378
- $aChars = array( 'abcdefghijkmnopqrstuvwxyz' );
379
- $aChars[] = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
380
-
381
- $sCharset = implode( '', $aChars );
382
- if ( $infBeginLetter ) {
383
- $sPassword = $sCharset[ ( rand() % strlen( $sCharset ) ) ];
384
  }
385
- else {
386
- $sPassword = '';
 
 
 
 
 
 
 
387
  }
388
- $sCharset .= '023456789';
389
-
390
- for ( $i = $infBeginLetter? 1 : 0; $i < $innLength; $i++ ) {
391
- $sPassword .= $sCharset[ ( rand() % strlen( $sCharset ) ) ];
 
 
 
392
  }
393
- return $sPassword;
394
- }
395
 
396
- /**
397
- * @param string $sKey
398
- * @return mixed|null
399
- */
400
- public static function FetchServer( $sKey ) {
401
- if ( function_exists( 'filter_input' ) && defined( 'INPUT_SERVER' ) ) {
402
- $sPossible = filter_input( INPUT_SERVER, $sKey );
403
- if ( !empty( $sPossible ) ) {
404
- return $sPossible;
405
- }
406
  }
407
- return self::ArrayFetch( $_SERVER, $sKey );
408
- }
409
 
410
- /**
411
- * @param string $sKey
412
- * @return mixed|null
413
- */
414
- public static function FetchEnv( $sKey ) {
415
- if ( function_exists( 'filter_input' ) && defined( 'INPUT_ENV' ) ) {
416
- $sPossible = filter_input( INPUT_ENV, $sKey );
417
- if ( !empty( $sPossible ) ) {
418
- return $sPossible;
419
  }
 
420
  }
421
- return self::ArrayFetch( $_ENV, $sKey );
422
- }
423
 
424
- /**
425
- * @param string $insKey
426
- * @param boolean $infIncludeCookie
427
- * @return mixed|null
428
- */
429
- public static function FetchRequest( $insKey, $infIncludeCookie = true ) {
430
- $mFetchVal = self::FetchPost( $insKey );
431
- if ( is_null( $mFetchVal ) ) {
432
- $mFetchVal = self::FetchGet( $insKey );
433
- if ( is_null( $mFetchVal && $infIncludeCookie ) ) {
434
- $mFetchVal = self::FetchCookie( $insKey );
435
  }
 
436
  }
437
- return $mFetchVal;
438
- }
439
- /**
440
- * @param string $insKey
441
- * @return mixed|null
442
- */
443
- public static function FetchGet( $insKey ) {
444
- if ( function_exists( 'filter_input' ) && defined( 'INPUT_GET' ) ) {
445
- return filter_input( INPUT_GET, $insKey );
446
- }
447
- return self::ArrayFetch( $_GET, $insKey );
448
- }
449
- /**
450
- * @param string $insKey The $_POST key
451
- * @return mixed|null
452
- */
453
- public static function FetchPost( $insKey ) {
454
- if ( function_exists( 'filter_input' ) && defined( 'INPUT_POST' ) ) {
455
- return filter_input( INPUT_POST, $insKey );
456
- }
457
- return self::ArrayFetch( $_POST, $insKey );
458
- }
459
- /**
460
- * @param string $insKey The $_POST key
461
- * @param mixed $mDefault
462
- * @return mixed|null
463
- */
464
- public static function FetchCookie( $insKey, $mDefault = null ) {
465
- if ( function_exists( 'filter_input' ) && defined( 'INPUT_COOKIE' ) ) {
466
- return filter_input( INPUT_COOKIE, $insKey );
467
- }
468
- return self::ArrayFetch( $_COOKIE, $insKey, $mDefault );
469
- }
470
 
471
- /**
472
- * @param array $inaArray
473
- * @param string $insKey The array key
474
- * @param mixed $mDefault
475
- * @return mixed|null
476
- */
477
- public static function ArrayFetch( &$inaArray, $insKey, $mDefault = null ) {
478
- if ( empty( $inaArray ) ) {
479
- return $mDefault;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
  }
481
- if ( !isset( $inaArray[$insKey] ) ) {
482
- return $mDefault;
 
 
 
 
 
 
 
 
 
 
 
 
483
  }
484
- return $inaArray[$insKey];
485
  }
486
- }
487
-
488
  endif;
489
 
490
  if ( !class_exists('ICWP_WPSF_DataProcessor') ):
491
- class ICWP_WPSF_DataProcessor extends ICWP_DataProcessor_V1 { }
 
 
 
 
 
 
 
 
 
 
 
492
  endif;
3
  /**
4
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
5
  * All rights reserved.
 
 
6
  *
7
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
8
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
  *
18
  */
19
 
20
+ if ( !class_exists('ICWP_WPSF_DataProcessor_V3') ):
21
+
22
+ class ICWP_WPSF_DataProcessor_V3 {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_DataProcessor_V3
26
+ */
27
+ protected static $oInstance = NULL;
28
+
29
+ /**
30
+ * @var bool
31
+ */
32
+ public static $fUseFilterInput = false;
33
+
34
+ /**
35
+ * @var string
36
+ */
37
+ protected static $sIpAddress;
38
+
39
+ /**
40
+ * @var integer
41
+ */
42
+ protected static $nRequestTime;
43
+
44
+ /**
45
+ * @return int
46
+ */
47
+ public static function GetRequestTime() {
48
+ if ( empty( self::$nRequestTime ) ) {
49
+ self::$nRequestTime = time();
50
+ }
51
+ return self::$nRequestTime;
52
  }
53
 
54
+ /**
55
+ * Cloudflare compatible.
56
+ *
57
+ * @param boolean $fAsLong
58
+ * @return bool|integer - visitor IP Address as IP2Long
59
+ */
60
+ public static function GetVisitorIpAddress( $fAsLong = true ) {
61
+
62
+ if ( !empty( self::$sIpAddress ) ) {
63
+ return $fAsLong? ip2long( self::$sIpAddress ) : self::$sIpAddress;
64
+ }
65
+
66
+ $aAddressSourceOptions = array(
67
+ 'HTTP_CF_CONNECTING_IP',
68
+ 'HTTP_CLIENT_IP',
69
+ 'HTTP_X_FORWARDED_FOR',
70
+ 'HTTP_X_FORWARDED',
71
+ 'HTTP_FORWARDED',
72
+ 'REMOTE_ADDR'
73
+ );
74
+ $fCanUseFilter = function_exists( 'filter_var' ) && defined( 'FILTER_FLAG_NO_PRIV_RANGE' ) && defined( 'FILTER_FLAG_IPV4' );
75
+
76
+ foreach( $aAddressSourceOptions as $sOption ) {
77
+
78
+ $sIpAddressToTest = self::FetchServer( $sOption );
79
+ if ( empty( $sIpAddressToTest ) ) {
80
  continue;
81
  }
82
+
83
+ $aIpAddresses = explode( ',', $sIpAddressToTest ); //sometimes a comma-separated list is returned
84
+ foreach( $aIpAddresses as $sIpAddress ) {
85
+
86
+ if ( $fCanUseFilter && !self::IsAddressInPublicIpRange( $sIpAddress ) ) {
87
+ continue;
88
+ }
89
+ else {
90
+ self::$sIpAddress = $sIpAddress;
91
+ return $fAsLong? ip2long( self::$sIpAddress ) : self::$sIpAddress;
92
+ }
93
+ }
94
+ }
95
+ return false;
96
+ }
97
+
98
+ /**
99
+ * For now will return true when it's a valid IPv4 or IPv6 address and you have access to filter_var()
100
+ *
101
+ * otherwise, if it's Ipv6 it'll return false always or will attempt to manually parse IPv4.
102
+ *
103
+ * @param string
104
+ * @return boolean
105
+ */
106
+ public static function GetIsValidIpAddress( $sIpAddress ) {
107
+ if ( function_exists('filter_var') && defined('FILTER_VALIDATE_IP') && defined('FILTER_FLAG_IPV4') && defined('FILTER_FLAG_IPV6') ) {
108
+
109
+ if ( filter_var( $sIpAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
110
+ return true;
111
+ }
112
  else {
113
+ return filter_var( $sIpAddress, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 );
 
114
  }
115
  }
116
+
117
+ if ( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/', $sIpAddress ) ) { //It's a valid IPv4 format, now check components
118
+ $aParts = explode( '.', $sIpAddress );
119
+ foreach ( $aParts as $sPart ) {
120
+ $sPart = intval( $sPart );
121
+ if ( $sPart < 0 || $sPart > 255 ) {
122
+ return false;
123
+ }
124
+ }
125
+ return true;
126
+ }
127
+
128
+ return false;
129
  }
 
 
130
 
131
+ /**
132
+ * Assumes a valid IPv4 address is provided as we're only testing for a whether the IP is public or not.
133
+ *
134
+ * @param string $sIpAddress
135
+ * @uses filter_var
136
+ * @return boolean
137
+ */
138
+ public static function IsAddressInPublicIpRange( $sIpAddress ) {
139
+ return function_exists('filter_var') && filter_var( $sIpAddress, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE );
 
 
 
 
 
 
 
 
140
  }
 
141
 
142
+ /**
143
+ * @param string $sAddresses
144
+ * @return Ambigous|array|unknown
145
+ */
146
+ static public function ExtractIpAddresses( $sAddresses = '' ) {
147
+
148
+ $aRawAddresses = array();
149
 
150
+ if ( empty( $sAddresses ) ) {
151
+ return $aRawAddresses;
 
 
152
  }
153
+ $aRawList = array_map( 'trim', explode( "\n", $sAddresses ) );
154
+
155
+ foreach( $aRawList as $sKey => $sRawAddressLine ) {
156
+
157
+ if ( empty( $sRawAddressLine ) ) {
158
+ continue;
159
+ }
160
+
161
+ // Each line can have a Label which is the IP separated with a space.
162
+ $aParts = explode( ' ', $sRawAddressLine, 2 );
163
+ if ( count( $aParts ) == 1 ) {
164
+ $aParts[] = '';
165
+ }
166
+ $aRawAddresses[ $aParts[0] ] = trim( $aParts[1] );
167
  }
168
+ return self::Add_New_Raw_Ips( array(), $aRawAddresses );
 
 
 
 
 
 
 
 
 
169
  }
170
+
171
+ /**
172
+ * @param string $sRawList
173
+ * @return array
174
+ */
175
+ static public function ExtractCommaSeparatedList( $sRawList = '' ) {
176
+
177
+ $aRawList = array();
178
+ if ( empty( $sRawList ) ) {
179
+ return $aRawList;
180
+ }
181
+
182
+ $aRawList = array_map( 'trim', preg_split( '/\r\n|\r|\n/', $sRawList ) );
183
+ $aNewList = array();
184
+ $fHadStar = false;
185
+ foreach( $aRawList as $sKey => $sRawLine ) {
186
+
187
+ if ( empty( $sRawLine ) ) {
188
  continue;
189
  }
190
+ $sRawLine = str_replace( ' ', '', $sRawLine );
191
+ $aParts = explode( ',', $sRawLine, 2 );
192
+ // we only permit 1x line beginning with *
193
+ if ( $aParts[0] == '*' ) {
194
+ if ( $fHadStar ) {
195
+ continue;
196
+ }
197
+ $fHadStar = true;
198
  }
199
+ else {
200
+ //If there's only 1 item on the line, we assume it to be a global
201
+ // parameter rule
202
+ if ( count( $aParts ) == 1 || empty( $aParts[1] ) ) { // there was no comma in this line in the first place
203
+ array_unshift( $aParts, '*' );
204
+ }
205
+ }
206
+
207
+ $aParams = empty( $aParts[1] )? array() : explode( ',', $aParts[1] );
208
+ $aNewList[ $aParts[0] ] = $aParams;
209
  }
210
+ return $aNewList;
 
 
211
  }
212
+
213
+ /**
214
+ * Given a list of new IPv4 address ($inaNewRawAddresses) it'll add them to the existing list
215
+ * ($inaCurrent) where they're not already found
216
+ *
217
+ * @param array $inaCurrent - the list to which to add the new addresses
218
+ * @param array $inaNewRawAddresses - the new IPv4 addresses
219
+ * @param int $outnNewAdded - the count of newly added IPs
220
+ * @return unknown|Ambigous <multitype:multitype: , string>
221
+ */
222
+ public static function Add_New_Raw_Ips( $inaCurrent, $inaNewRawAddresses, &$outnNewAdded = 0 ) {
223
+
224
+ $outnNewAdded = 0;
225
+
226
+ if ( empty( $inaNewRawAddresses ) ) {
227
+ return $inaCurrent;
228
+ }
229
+
230
+ if ( !array_key_exists( 'ips', $inaCurrent ) ) {
231
+ $inaCurrent['ips'] = array();
232
+ }
233
+ if ( !array_key_exists( 'meta', $inaCurrent ) ) {
234
+ $inaCurrent['meta'] = array();
235
+ }
236
+
237
+ foreach( $inaNewRawAddresses as $sRawIpAddress => $sLabel ) {
238
+ $mVerifiedIp = self::Verify_Ip( $sRawIpAddress );
239
+ if ( $mVerifiedIp !== false && !in_array( $mVerifiedIp, $inaCurrent['ips'] ) ) {
240
+ $inaCurrent['ips'][] = $mVerifiedIp;
241
+ if ( empty($sLabel) ) {
242
+ $sLabel = 'no label';
243
+ }
244
+ $inaCurrent['meta'][ md5( $mVerifiedIp ) ] = $sLabel;
245
+ $outnNewAdded++;
246
+ }
247
+ }
248
  return $inaCurrent;
249
  }
 
 
 
 
 
 
 
250
 
251
+ /**
252
+ * @param array $inaCurrent
253
+ * @param array $inaRawAddresses - should be a plain numerical array of IPv4 addresses
254
+ * @return array:
255
+ */
256
+ public static function Remove_Raw_Ips( $inaCurrent, $inaRawAddresses ) {
257
+ if ( empty( $inaRawAddresses ) ) {
258
+ return $inaCurrent;
259
+ }
260
+
261
+ if ( !array_key_exists( 'ips', $inaCurrent ) ) {
262
+ $inaCurrent['ips'] = array();
263
+ }
264
+ if ( !array_key_exists( 'meta', $inaCurrent ) ) {
265
+ $inaCurrent['meta'] = array();
266
+ }
267
+
268
+ foreach( $inaRawAddresses as $sRawIpAddress ) {
269
+ $mVerifiedIp = self::Verify_Ip( $sRawIpAddress );
270
+ if ( $mVerifiedIp === false ) {
271
+ continue;
272
+ }
273
+ $mKey = array_search( $mVerifiedIp, $inaCurrent['ips'] );
274
+ if ( $mKey !== false ) {
275
+ unset( $inaCurrent['ips'][$mKey] );
276
+ unset( $inaCurrent['meta'][ md5( $mVerifiedIp ) ] );
277
  }
 
 
278
  }
 
 
 
 
 
 
 
 
 
 
 
279
  return $inaCurrent;
280
  }
281
+
282
+ /**
283
+ * @param string $sIpAddress
284
+ * @return bool|int|string
285
+ */
286
+ public static function Verify_Ip( $sIpAddress ) {
287
+
288
+ $sAddress = self::Clean_Ip( $sIpAddress );
289
+
290
+ // Now, determine if this is an IP range, or just a plain IP address.
291
+ if ( strpos( $sAddress, '-' ) === false ) { //plain IP address
292
+ return self::Verify_Ip_Address( $sAddress );
293
  }
294
+ else {
295
+ return self::Verify_Ip_Range( $sAddress );
 
 
296
  }
297
  }
298
+
299
+ /**
300
+ * @param string $insRawAddress
301
+ * @return mixed
302
+ */
303
+ public static function Clean_Ip( $insRawAddress ) {
304
+ $insRawAddress = preg_replace( '/[a-z\s]/i', '', $insRawAddress );
305
+ $insRawAddress = str_replace( '.', 'PERIOD', $insRawAddress );
306
+ $insRawAddress = str_replace( '-', 'HYPEN', $insRawAddress );
307
+ $insRawAddress = preg_replace( '/[^a-z0-9]/i', '', $insRawAddress );
308
+ $insRawAddress = str_replace( 'PERIOD', '.', $insRawAddress );
309
+ $insRawAddress = str_replace( 'HYPEN', '-', $insRawAddress );
310
+ return $insRawAddress;
311
  }
 
312
 
313
+ /**
314
+ * Taken from http://www.phacks.net/detecting-search-engine-bot-and-web-spiders/
315
+ */
316
+ public static function IsSearchEngineBot() {
317
+
318
+ $sUserAgent = self::FetchServer( 'HTTP_USER_AGENT' );
319
+ if ( empty( $sUserAgent ) ) {
320
+ return false;
 
 
 
 
 
 
321
  }
322
+
323
+ $sBots = 'Googlebot|bingbot|Twitterbot|Baiduspider|ia_archiver|R6_FeedFetcher|NetcraftSurveyAgent'
324
+ .'|Sogou web spider|Yahoo! Slurp|facebookexternalhit|PrintfulBot|msnbot|UnwindFetchor|urlresolver|Butterfly|TweetmemeBot';
325
+
326
+ return ( preg_match( "/$sBots/", $sUserAgent ) > 0 );
327
  }
328
+
329
+ /**
330
+ * Returns IP Address as long if verified.
331
+ *
332
+ * @param string $sIpAddress
333
+ * @return bool|int
334
+ */
335
+ public static function Verify_Ip_Address( $sIpAddress ) {
336
+ return self::GetIsValidIpAddress( $sIpAddress ) ? ip2long( $sIpAddress ) : false;
 
 
337
  }
 
 
338
 
339
+ /**
340
+ * The only ranges currently accepted are a.b.c.d-f.g.h.j
341
+ *
342
+ * @param string $sIpAddressRange
343
+ * @return string|boolean
344
+ */
345
+ public static function Verify_Ip_Range( $sIpAddressRange ) {
346
+
347
+ list( $sIpRangeStart, $sIpRangeEnd ) = explode( '-', $sIpAddressRange, 2 );
348
+
349
+ if ( $sIpRangeStart == $sIpRangeEnd ) {
350
+ return self::Verify_Ip_Address( $sIpRangeStart );
351
+ }
352
+ else if ( self::Verify_Ip_Address( $sIpRangeStart ) && self::Verify_Ip_Address( $sIpRangeEnd ) ) {
353
+ $nStart = ip2long( $sIpRangeStart );
354
+ $nEnd = ip2long( $sIpRangeEnd );
355
 
356
+ // do our best to order it
357
+ if (
358
+ ( $nStart > 0 && $nEnd > 0 && $nStart > $nEnd )
359
+ || ( $nStart < 0 && $nEnd < 0 && $nStart > $nEnd )
360
+ ) {
361
+ $nTemp = $nStart;
362
+ $nStart = $nEnd;
363
+ $nEnd = $nTemp;
364
+ }
365
+ return $nStart.'-'.$nEnd;
366
+ }
367
  return false;
368
  }
369
+
370
+ /**
371
+ * @param $sRawKeys
372
+ * @return array
373
+ */
374
+ public static function CleanYubikeyUniqueKeys( $sRawKeys ) {
375
+ $aKeys = explode( "\n", $sRawKeys );
376
+ foreach( $aKeys as $nIndex => $sUsernameKey ) {
377
+ if ( empty( $sUsernameKey ) ) {
378
+ unset( $aKeys[$nIndex] );
379
+ continue;
380
+ }
381
+ $aParts = array_map( 'trim', explode( ',', $sUsernameKey ) );
382
+ if ( empty( $aParts[0] ) || empty( $aParts[1] ) || strlen( $aParts[1] ) < 12 ) {
383
+ unset( $aKeys[$nIndex] );
384
+ continue;
385
+ }
386
+ $aParts[1] = substr( $aParts[1], 0, 12 );
387
+ $aKeys[$nIndex] = array( $aParts[0] => $aParts[1] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  }
389
+ return $aKeys;
390
  }
 
 
391
 
392
+ /**
393
+ * @param integer $nLength
394
+ * @param boolean $fBeginLetter
395
+ * @return string
396
+ */
397
+ static public function GenerateRandomString( $nLength = 10, $fBeginLetter = false ) {
398
+ $aChars = array( 'abcdefghijkmnopqrstuvwxyz' );
399
+ $aChars[] = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
400
+
401
+ $sCharset = implode( '', $aChars );
402
+ if ( $fBeginLetter ) {
403
+ $sPassword = $sCharset[ ( rand() % strlen( $sCharset ) ) ];
404
+ }
405
+ else {
406
+ $sPassword = '';
407
  }
408
+ $sCharset .= '023456789';
409
+
410
+ for ( $i = $fBeginLetter? 1 : 0; $i < $nLength; $i++ ) {
411
+ $sPassword .= $sCharset[ ( rand() % strlen( $sCharset ) ) ];
412
  }
413
+ return $sPassword;
 
414
  }
 
 
415
 
416
+ /**
417
+ * @return bool
418
+ */
419
+ static public function GetIsRequestPost() {
420
+ return ( self::GetRequestMethod() == 'post' );
 
 
 
 
 
 
 
421
  }
422
+
423
+ /**
424
+ * Returns the current request method as an all-lower-case string
425
+ *
426
+ * @return bool|string
427
+ */
428
+ static public function GetRequestMethod() {
429
+ $sRequestMethod = self::FetchServer( 'REQUEST_METHOD' );
430
+ return ( empty( $sRequestMethod ) ? false : strtolower( $sRequestMethod ) );
431
  }
432
+
433
+ /**
434
+ * @return string|null
435
+ */
436
+ static public function GetScriptName() {
437
+ $sScriptName = self::FetchServer( 'SCRIPT_NAME' );
438
+ return !empty( $sScriptName )? $sScriptName : self::FetchServer( 'PHP_SELF' );
439
  }
 
 
440
 
441
+ /**
442
+ * @return bool
443
+ */
444
+ static public function GetUseFilterInput() {
445
+ return self::$fUseFilterInput && function_exists( 'filter_input' );
 
 
 
 
 
446
  }
 
 
447
 
448
+ /**
449
+ * @param array $aArray
450
+ * @param string $sKey The array key to fetch
451
+ * @param mixed $mDefault
452
+ * @return mixed|null
453
+ */
454
+ public static function ArrayFetch( &$aArray, $sKey, $mDefault = null ) {
455
+ if ( empty( $aArray ) || !isset( $aArray[$sKey] ) ) {
456
+ return $mDefault;
457
  }
458
+ return $aArray[$sKey];
459
  }
 
 
460
 
461
+ /**
462
+ * @param string $sKey The $_COOKIE key
463
+ * @param mixed $mDefault
464
+ * @return mixed|null
465
+ */
466
+ public static function FetchCookie( $sKey, $mDefault = null ) {
467
+ if ( self::GetUseFilterInput() && defined( 'INPUT_COOKIE' ) ) {
468
+ $mPossible = filter_input( INPUT_COOKIE, $sKey );
469
+ if ( !empty( $mPossible ) ) {
470
+ return $mPossible;
471
+ }
472
  }
473
+ return self::ArrayFetch( $_COOKIE, $sKey, $mDefault );
474
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
 
476
+ /**
477
+ * @param string $sKey
478
+ * @param mixed $mDefault
479
+ * @return mixed|null
480
+ */
481
+ public static function FetchEnv( $sKey, $mDefault = null ) {
482
+ if ( self::GetUseFilterInput() && defined( 'INPUT_ENV' ) ) {
483
+ $sPossible = filter_input( INPUT_ENV, $sKey );
484
+ if ( !empty( $sPossible ) ) {
485
+ return $sPossible;
486
+ }
487
+ }
488
+ return self::ArrayFetch( $_ENV, $sKey, $mDefault );
489
+ }
490
+ /**
491
+ * @param string $sKey
492
+ * @param mixed $mDefault
493
+ * @return mixed|null
494
+ */
495
+ public static function FetchGet( $sKey, $mDefault = null ) {
496
+ if ( self::GetUseFilterInput() && defined( 'INPUT_GET' ) ) {
497
+ $mPossible = filter_input( INPUT_GET, $sKey );
498
+ if ( !empty( $mPossible ) ) {
499
+ return $mPossible;
500
+ }
501
+ }
502
+ return self::ArrayFetch( $_GET, $sKey, $mDefault );
503
+ }
504
+ /**
505
+ * @param string $sKey The $_POST key
506
+ * @param mixed $mDefault
507
+ * @return mixed|null
508
+ */
509
+ public static function FetchPost( $sKey, $mDefault = null ) {
510
+ if ( self::GetUseFilterInput() && defined( 'INPUT_POST' ) ) {
511
+ $mPossible = filter_input( INPUT_POST, $sKey );
512
+ if ( !empty( $mPossible ) ) {
513
+ return $mPossible;
514
+ }
515
+ }
516
+ return self::ArrayFetch( $_POST, $sKey, $mDefault );
517
+ }
518
+ /**
519
+ * @param string $sKey
520
+ * @param boolean $infIncludeCookie
521
+ * @param mixed $mDefault
522
+ * @return mixed|null
523
+ */
524
+ public static function FetchRequest( $sKey, $infIncludeCookie = true, $mDefault = null ) {
525
+ $mFetchVal = self::FetchPost( $sKey );
526
+ if ( is_null( $mFetchVal ) ) {
527
+ $mFetchVal = self::FetchGet( $sKey );
528
+ if ( is_null( $mFetchVal && $infIncludeCookie ) ) {
529
+ $mFetchVal = self::FetchCookie( $sKey );
530
+ }
531
+ }
532
+ return is_null( $mFetchVal )? $mDefault : $mFetchVal;
533
  }
534
+
535
+ /**
536
+ * @param string $sKey
537
+ * @param mixed $mDefault
538
+ * @return mixed|null
539
+ */
540
+ public static function FetchServer( $sKey, $mDefault = null ) {
541
+ if ( self::GetUseFilterInput() && defined( 'INPUT_SERVER' ) ) {
542
+ $sPossible = filter_input( INPUT_SERVER, $sKey );
543
+ if ( !empty( $sPossible ) ) {
544
+ return $sPossible;
545
+ }
546
+ }
547
+ return self::ArrayFetch( $_SERVER, $sKey, $mDefault );
548
  }
 
549
  }
 
 
550
  endif;
551
 
552
  if ( !class_exists('ICWP_WPSF_DataProcessor') ):
553
+
554
+ class ICWP_WPSF_DataProcessor extends ICWP_WPSF_DataProcessor_V3 {
555
+ /**
556
+ * @return ICWP_WPSF_DataProcessor
557
+ */
558
+ public static function GetInstance() {
559
+ if ( is_null( self::$oInstance ) ) {
560
+ self::$oInstance = new self();
561
+ }
562
+ return self::$oInstance;
563
+ }
564
+ }
565
  endif;
src/icwp-foundation.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class ICWP_WPSF_Foundation {
4
+
5
+ /**
6
+ * @return ICWP_WPSF_DataProcessor
7
+ */
8
+ public function loadDataProcessor() {
9
+ require_once( 'icwp-data-processor.php' );
10
+ return ICWP_WPSF_DataProcessor::GetInstance();
11
+ }
12
+
13
+ /**
14
+ * @return ICWP_WPSF_WpFilesystem
15
+ */
16
+ public function loadFileSystemProcessor() {
17
+ require_once( 'icwp-wpfilesystem.php' );
18
+ return ICWP_WPSF_WpFilesystem::GetInstance();
19
+ }
20
+
21
+ /**
22
+ * @return ICWP_WPSF_WpFunctions
23
+ */
24
+ public function loadWpFunctionsProcessor() {
25
+ require_once( 'icwp-wpfunctions.php' );
26
+ return ICWP_WPSF_WpFunctions::GetInstance();
27
+ }
28
+
29
+ /**
30
+ * @return ICWP_WPSF_YamlProcessor
31
+ */
32
+ public function loadYamlProcessor() {
33
+ require_once( 'icwp-processor-yaml.php' );
34
+ return ICWP_WPSF_YamlProcessor::GetInstance();
35
+ }
36
+
37
+ /**
38
+ * @return ICWP_Stats_WPSF
39
+ */
40
+ public function loadStatsProcessor() {
41
+ require_once( 'icwp-wpsf-stats.php' );
42
+ }
43
+
44
+ }
src/icwp-import-base-processor.php DELETED
@@ -1,84 +0,0 @@
1
- <?php
2
- /**
3
- * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
- * All rights reserved.
5
- *
6
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
- *
17
- */
18
-
19
- require_once( dirname(__FILE__).'/icwp-base-processor.php' );
20
- require_once( dirname(__FILE__).'/icwp-data-processor.php' );
21
-
22
- if ( !class_exists('ICWP_ImportBaseProcessor') ):
23
-
24
- class ICWP_ImportBaseProcessor extends ICWP_WPSF_BaseProcessor {
25
-
26
- /**
27
- * The options prefix used by the target plugin
28
- * @var string
29
- */
30
- protected $m_sOptionPrefix;
31
-
32
- /**
33
- * The value of all the options of the source plugin (keys of the options map array)
34
- * @var array
35
- */
36
- protected $m_aSourceValues;
37
-
38
- /**
39
- * An associative array of option keys from the source plugin mapped to the keys of the target plugin
40
- * @var unknown_type
41
- */
42
- protected $m_aOptionsMap;
43
-
44
- public function __construct( $sTargetOptionPrefix = '' ) {
45
- $this->m_sOptionPrefix = $sTargetOptionPrefix;
46
- }
47
-
48
- public function runImport() {
49
- $this->populateSourceOptions();
50
- $this->mapOptionsToTarget();
51
- }
52
-
53
- protected function mapOptionsToTarget() { }
54
-
55
- /**
56
- * Uses the keys from the Options Map array and populates the source value array with the database values.
57
- */
58
- protected function populateSourceOptions() {
59
- foreach( $this->m_aOptionsMap as $sOptionName => $sTarget ) {
60
- $this->m_aSourceValues[ $sOptionName ] = get_option( $sOptionName );
61
- }
62
- }
63
-
64
- /**
65
- * Updates the target plugin options with the values (using the options prefix)
66
- *
67
- * @param string $insKey
68
- * @param string|mixed $inmValue
69
- */
70
- protected function updateTargetOption( $insKey, $inmValue ) {
71
- $fResult = update_option( $this->m_sOptionPrefix.$insKey, $inmValue );
72
- }
73
-
74
- /**
75
- * Gets the target plugin option value for the key (using the options prefix)
76
- *
77
- * @param string $insKey
78
- */
79
- protected function getTargetOption( $insKey ) {
80
- return get_option( $this->m_sOptionPrefix.$insKey );
81
- }
82
- }
83
-
84
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/icwp-import-wpf2-processor.php DELETED
@@ -1,147 +0,0 @@
1
- <?php
2
- /**
3
- * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
- * All rights reserved.
5
- *
6
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
- */
17
-
18
- require_once( dirname(__FILE__).'/icwp-import-base-processor.php' );
19
-
20
- if ( !class_exists('ICWP_ImportWpf2Processor') ):
21
-
22
- class ICWP_ImportWpf2Processor extends ICWP_ImportBaseProcessor {
23
-
24
- /**
25
- * @var ICWP_WPSF_FeatureHandler_Plugin
26
- */
27
- protected $m_oWpsfOptions;
28
- /**
29
- * @var ICWP_WPSF_FeatureHandler_Firewall
30
- */
31
- protected $m_oFirewallOptions;
32
-
33
- public function __construct( $inoPluginOptions, $inoFirewallOptions ) {
34
-
35
- $this->m_oWpsfOptions = $inoPluginOptions;
36
- $this->m_oFirewallOptions = $inoFirewallOptions;
37
-
38
- $this->m_aOptionsMap = array(
39
- 'WP_firewall_redirect_page' => 'block_response',
40
- 'WP_firewall_email_enable' => 'block_send_email',
41
- /* 'WP_firewall_email_type' => '', unused */
42
- 'WP_firewall_email_address' => 'block_send_email_address',
43
- 'WP_firewall_exclude_directory' => 'block_dir_traversal',
44
- 'WP_firewall_exclude_queries' => 'block_sql_queries',
45
- 'WP_firewall_exclude_terms' => 'block_wordpress_terms',
46
- 'WP_firewall_exclude_spaces' => 'block_field_truncation',
47
- 'WP_firewall_exclude_file' => 'block_exe_file_uploads',
48
- 'WP_firewall_exclude_http' => 'block_leading_schema',
49
- 'WP_firewall_whitelisted_ip' => 'ips_whitelist',
50
- 'WP_firewall_whitelisted_page' => 'page_params_whitelist',
51
- 'WP_firewall_whitelisted_variable' => 'page_params_whitelist',
52
- /* 'WP_firewall_plugin_url' => '', unused */
53
- /* 'WP_firewall_default_whitelisted_page' => '', unused */
54
- /* 'WP_firewall_previous_attack_var' => '', unused */
55
- /* 'WP_firewall_previous_attack_ip' => '', unused */
56
- /* 'WP_firewall_email_limit' => '', unused */
57
- );
58
- }
59
-
60
- protected function mapOptionsToTarget() {
61
-
62
- $aPluginOptions = array(
63
- 'block_send_email_address'
64
- );
65
-
66
- $aFirewallOptions = array(
67
- 'block_response',
68
- 'block_send_email',
69
- 'block_send_email_address',
70
- 'block_dir_traversal',
71
- 'block_sql_queries',
72
- 'block_wordpress_terms',
73
- 'block_field_truncation',
74
- 'block_exe_file_uploads',
75
- 'block_leading_schema',
76
- 'ips_whitelist',
77
- 'page_params_whitelist',
78
- 'page_params_whitelist'
79
- );
80
-
81
- //redirect option
82
- if ( $this->m_aSourceValues[ 'WP_firewall_redirect_page' ] == 'homepage' ) {
83
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_redirect_page'], 'redirect_home' );
84
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_redirect_page'], 'redirect_home' );
85
- }
86
- else if ( $this->m_aSourceValues[ 'WP_firewall_redirect_page' ] == '404page' ) {
87
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_redirect_page'], 'redirect_404' );
88
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_redirect_page'], 'redirect_404' );
89
- }
90
-
91
- //Email enable
92
- if ( $this->m_aSourceValues[ 'WP_firewall_email_enable' ] == 'enable' ) {
93
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_email_enable'], 'Y' );
94
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_email_enable'], 'Y' );
95
- }
96
- else { // actually the WPF2 doesn't give the option to turn off email(!)
97
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_email_enable'], 'N' );
98
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_email_enable'], 'N' );
99
- }
100
-
101
- //Email address
102
- $this->m_oWpsfOptions->setOpt( $this->m_aOptionsMap['WP_firewall_email_address'], $this->m_aSourceValues[ 'WP_firewall_email_address' ] );
103
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_email_address'], $this->m_aSourceValues[ 'WP_firewall_email_address' ] );
104
-
105
- //Firewall block options - uses 'allow' to signify the block is in place. :|
106
- $sTargetValue = ( $this->m_aSourceValues[ 'WP_firewall_exclude_directory' ] == 'allow' )? 'Y' : 'N';
107
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_exclude_directory'], $sTargetValue );
108
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_exclude_directory'], $sTargetValue );
109
- $sTargetValue = ( $this->m_aSourceValues[ 'WP_firewall_exclude_queries' ] == 'allow' )? 'Y' : 'N';
110
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_exclude_queries'], $sTargetValue );
111
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_exclude_queries'], $sTargetValue );
112
- $sTargetValue = ( $this->m_aSourceValues[ 'WP_firewall_exclude_terms' ] == 'allow' )? 'Y' : 'N';
113
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_exclude_terms'], $sTargetValue );
114
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_exclude_terms'], $sTargetValue );
115
- $sTargetValue = ( $this->m_aSourceValues[ 'WP_firewall_exclude_spaces' ] == 'allow' )? 'Y' : 'N';
116
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_exclude_spaces'], $sTargetValue );
117
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_exclude_spaces'], $sTargetValue );
118
- $sTargetValue = ( $this->m_aSourceValues[ 'WP_firewall_exclude_file' ] == 'allow' )? 'Y' : 'N';
119
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_exclude_file'], $sTargetValue );
120
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_exclude_file'], $sTargetValue );
121
- $sTargetValue = ( $this->m_aSourceValues[ 'WP_firewall_exclude_http' ] == 'allow' )? 'Y' : 'N';
122
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_exclude_http'], $sTargetValue );
123
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_exclude_http'], $sTargetValue );
124
-
125
- // Cookie checking - WPF2 does this by default
126
- // $this->updateTargetOption( 'include_cookie_checks', 'Y' );
127
- $this->m_oFirewallOptions->setOpt( 'include_cookie_checks', 'Y' );
128
-
129
- // Whitelisted IPs
130
- $aSourceIps = maybe_unserialize( $this->m_aSourceValues[ 'WP_firewall_whitelisted_ip' ] );
131
- $aNewList = array();
132
- foreach( $aSourceIps as $sIp ) {
133
- $aNewList[ $sIp ] = '';
134
- }
135
- $aTargetIpWhitelist = $this->m_oFirewallOptions->getOpt( $this->m_aOptionsMap['WP_firewall_whitelisted_ip'] );
136
- if ( empty( $aTargetIpWhitelist ) ) {
137
- $aTargetIpWhitelist = array();
138
- }
139
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_whitelisted_ip'], ICWP_WPSF_DataProcessor::Add_New_Raw_Ips( $aTargetIpWhitelist, $aNewList ) );
140
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_whitelisted_ip'], ICWP_WPSF_DataProcessor::Add_New_Raw_Ips( $aTargetIpWhitelist, $aNewList ) );
141
-
142
- // Whitelisted Pages and Vars... maybe later :|
143
- }
144
-
145
- }
146
-
147
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/icwp-options-vo.php ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class ICWP_WPSF_OptionsVO extends ICWP_WPSF_Foundation {
3
+
4
+ /**
5
+ * @var array
6
+ */
7
+ protected $aOptionsValues;
8
+
9
+ /**
10
+ * @var array
11
+ */
12
+ protected $aRawOptionsConfigData;
13
+
14
+ /**
15
+ * @var boolean
16
+ */
17
+ protected $fNeedSave;
18
+
19
+ /**
20
+ * @var string
21
+ */
22
+ protected $aOptionsKeys;
23
+
24
+ /**
25
+ * @var string
26
+ */
27
+ protected $sOptionsStorageKey;
28
+
29
+ /**
30
+ * @var string
31
+ */
32
+ protected $sOptionsName;
33
+
34
+ /**
35
+ * @param string $sOptionsName
36
+ */
37
+ public function __construct( $sOptionsName ) {
38
+ $this->sOptionsName = $sOptionsName;
39
+ }
40
+
41
+ /**
42
+ * @return bool
43
+ */
44
+ public function doOptionsSave() {
45
+ $this->cleanOptions();
46
+ if ( !$this->getNeedSave() ) {
47
+ return true;
48
+ }
49
+ $oWpFunc = $this->loadWpFunctionsProcessor();
50
+ $this->setNeedSave( false );
51
+ return $oWpFunc->updateOption( $this->getOptionsStorageKey(), $this->getAllOptionsValues() );
52
+ }
53
+
54
+ /**
55
+ * @return bool
56
+ */
57
+ public function doOptionsDelete() {
58
+ $oWpFunc = $this->loadWpFunctionsProcessor();
59
+ return $oWpFunc->deleteOption( $this->getOptionsStorageKey() );
60
+ }
61
+
62
+ /**
63
+ * @return array
64
+ */
65
+ public function getAllOptionsValues() {
66
+ return $this->loadOptionsValuesFromStorage();
67
+ }
68
+
69
+ /**
70
+ * @param $sProperty
71
+ * @return null|mixed
72
+ */
73
+ public function getFeatureProperty( $sProperty ) {
74
+ $aRawConfig = $this->getRawData_FullFeatureConfig();
75
+ return ( isset( $aRawConfig['properties'] ) && isset( $aRawConfig['properties'][$sProperty] ) ) ? $aRawConfig['properties'][$sProperty] : null;
76
+ }
77
+
78
+ /**
79
+ * @param string $sKey
80
+ * @return boolean
81
+ */
82
+ public function getIsOptionKey( $sKey ) {
83
+ return in_array( $sKey, $this->getOptionsKeys() );
84
+ }
85
+
86
+ /**
87
+ * Determines whether the given option key is a valid option
88
+ *
89
+ * @param string
90
+ * @return boolean
91
+ */
92
+ public function getIsValidOptionKey( $sOptionKey ) {
93
+ return in_array( $sOptionKey, $this->getOptionsKeys() );
94
+ }
95
+
96
+ /**
97
+ * @return array
98
+ */
99
+ public function getLegacyOptionsConfigData() {
100
+
101
+ $aRawData = $this->getRawData_FullFeatureConfig();
102
+ $aLegacyData = array();
103
+
104
+ foreach( $aRawData['sections'] as $nPosition => $aRawSection ) {
105
+
106
+ if ( isset( $aRawSection['hidden'] ) && $aRawSection['hidden'] ) {
107
+ continue;
108
+ }
109
+
110
+ $aLegacySection = array();
111
+ $aLegacySection['section_primary'] = isset( $aRawSection['primary'] ) && $aRawSection['primary'];
112
+ $aLegacySection['section_slug'] = $aRawSection['slug'];
113
+ $aLegacySection['section_options'] = array();
114
+ foreach( $this->getRawData_AllOptions() as $aRawOption ) {
115
+
116
+ if ( $aRawOption['section'] != $aRawSection['slug'] ) {
117
+ continue;
118
+ }
119
+
120
+ if ( isset( $aRawOption['hidden'] ) && $aRawOption['hidden'] ) {
121
+ continue;
122
+ }
123
+
124
+ $aLegacyRawOption = array();
125
+ $aLegacyRawOption['key'] = $aRawOption['key'];
126
+ $aLegacyRawOption['value'] = ''; //value
127
+ $aLegacyRawOption['default'] = $aRawOption['default'];
128
+ $aLegacyRawOption['type'] = $aRawOption['type'];
129
+
130
+ $aLegacyRawOption['value_options'] = array();
131
+ if ( in_array( $aLegacyRawOption['type'], array( 'select', 'multiple_select' ) ) ) {
132
+ foreach( $aRawOption['value_options'] as $aValueOptions ) {
133
+ $aLegacyRawOption['value_options'][ $aValueOptions['value_key'] ] = $aValueOptions['text'];
134
+ }
135
+ }
136
+
137
+ $aLegacyRawOption['info_link'] = isset( $aRawOption['link_info'] ) ? $aRawOption['link_info'] : '';
138
+ $aLegacyRawOption['blog_link'] = isset( $aRawOption['link_blog'] ) ? $aRawOption['link_blog'] : '';
139
+ $aLegacySection['section_options'][] = $aLegacyRawOption;
140
+ }
141
+
142
+ if ( count( $aLegacySection['section_options'] ) > 0 ) {
143
+ $aLegacyData[ $nPosition ] = $aLegacySection;
144
+ }
145
+ }
146
+ return $aLegacyData;
147
+ }
148
+
149
+ /**
150
+ * @return string
151
+ */
152
+ public function getNeedSave() {
153
+ return $this->fNeedSave;
154
+ }
155
+
156
+ /**
157
+ * @param string $sOptionKey
158
+ * @param mixed $mDefault
159
+ * @return mixed
160
+ */
161
+ public function getOpt( $sOptionKey, $mDefault = false ) {
162
+ $aOptionsValues = $this->getAllOptionsValues();
163
+ if ( !isset( $aOptionsValues[ $sOptionKey ] ) ) {
164
+ $this->setOpt( $sOptionKey, $this->getOptDefault( $sOptionKey, $mDefault ), true );
165
+ }
166
+ return $this->aOptionsValues[ $sOptionKey ];
167
+ }
168
+
169
+ /**
170
+ * @param string $sOptionKey
171
+ * @param mixed $mDefault
172
+ * @return mixed|null
173
+ */
174
+ public function getOptDefault( $sOptionKey, $mDefault = null ) {
175
+ $aOptions = $this->getRawData_AllOptions();
176
+ foreach( $aOptions as $aOption ) {
177
+ if ( $aOption['key'] == $sOptionKey ) {
178
+ if ( isset( $aOption['value'] ) ) {
179
+ return $aOption['value'];
180
+ }
181
+ else if ( isset( $aOption['default'] ) ) {
182
+ return $aOption['default'];
183
+ }
184
+ }
185
+ }
186
+ return $mDefault;
187
+ }
188
+
189
+ /**
190
+ * @param $sKey
191
+ * @param mixed $mValueToTest
192
+ * @param boolean $fStrict
193
+ * @return bool
194
+ */
195
+ public function getOptIs( $sKey, $mValueToTest, $fStrict = false ) {
196
+ $mOptionValue = $this->getOpt( $sKey );
197
+ return $fStrict? $mOptionValue === $mValueToTest : $mOptionValue == $mValueToTest;
198
+ }
199
+
200
+ /**
201
+ * @return string
202
+ */
203
+ public function getOptionsKeys() {
204
+ if ( !isset( $this->aOptionsKeys ) ) {
205
+ $this->aOptionsKeys = array();
206
+ foreach( $this->getRawData_AllOptions() as $aOption ) {
207
+ $this->aOptionsKeys[] = $aOption['key'];
208
+ }
209
+ }
210
+ return $this->aOptionsKeys;
211
+ }
212
+
213
+ /**
214
+ * @return string
215
+ */
216
+ public function getOptionsStorageKey() {
217
+ return $this->sOptionsStorageKey;
218
+ }
219
+
220
+ /**
221
+ * @return array
222
+ */
223
+ public function getRawData_FullFeatureConfig() {
224
+ if ( empty( $this->aRawOptionsConfigData ) ) {
225
+ $this->aRawOptionsConfigData = $this->readYamlConfiguration( $this->sOptionsName );
226
+ }
227
+ return $this->aRawOptionsConfigData;
228
+ }
229
+
230
+ /**
231
+ * Return the section of the Raw config that is the "options" key only.
232
+ *
233
+ * @return array
234
+ */
235
+ protected function getRawData_AllOptions() {
236
+ $aAllRawOptions = $this->getRawData_FullFeatureConfig();
237
+ return isset( $aAllRawOptions['options'] ) ? $aAllRawOptions['options'] : array();
238
+ }
239
+
240
+ /**
241
+ * Return the section of the Raw config that is the "options" key only.
242
+ *
243
+ * @param string $sOptionKey
244
+ * @return array
245
+ */
246
+ public function getRawData_SingleOption( $sOptionKey ) {
247
+ $aAllRawOptions = $this->getRawData_AllOptions();
248
+ foreach( $aAllRawOptions as $aOption ) {
249
+ if ( $sOptionKey == $aOption['key'] ) {
250
+ return $aOption;
251
+ }
252
+ }
253
+ return null;
254
+ }
255
+
256
+ /**
257
+ * @param string $sOptionKey
258
+ * @return boolean
259
+ */
260
+ public function resetOptToDefault( $sOptionKey ) {
261
+ return $this->setOpt( $sOptionKey, $this->getOptDefault( $sOptionKey ), true );
262
+ }
263
+
264
+ /**
265
+ * @param string $sKey
266
+ */
267
+ public function setOptionsStorageKey( $sKey ) {
268
+ $this->sOptionsStorageKey = $sKey;
269
+ }
270
+
271
+ /**
272
+ * @param boolean $fNeed
273
+ */
274
+ public function setNeedSave( $fNeed ) {
275
+ $this->fNeedSave = $fNeed;
276
+ }
277
+
278
+ /**
279
+ * @param string $sOptionKey
280
+ * @param mixed $mValue
281
+ * @param boolean $fForce
282
+ * @return mixed
283
+ */
284
+ public function setOpt( $sOptionKey, $mValue, $fForce = false ) {
285
+
286
+ if ( $fForce || $this->getOpt( $sOptionKey ) !== $mValue ) {
287
+ $this->setNeedSave( true );
288
+
289
+ //Load the config and do some pre-set verification where possible. This will slowly grow.
290
+ $aOption = $this->getRawData_SingleOption( $sOptionKey );
291
+ if ( !empty( $aOption['type'] ) ) {
292
+ if ( $aOption['type'] == 'boolean' && !is_bool( $mValue ) ) {
293
+ return $this->resetOptToDefault( $sOptionKey );
294
+ }
295
+ }
296
+
297
+ $this->aOptionsValues[ $sOptionKey ] = $mValue;
298
+ }
299
+ return true;
300
+ }
301
+
302
+ /**
303
+ * @param string $sOptionKey
304
+ * @return mixed
305
+ */
306
+ public function unsetOpt( $sOptionKey ) {
307
+
308
+ unset( $this->aOptionsValues[$sOptionKey] );
309
+ $this->setNeedSave( true );
310
+ return true;
311
+ }
312
+
313
+ /** PRIVATE STUFF */
314
+
315
+ /**
316
+ */
317
+ private function cleanOptions() {
318
+ if ( empty( $this->aOptionsValues ) || !is_array( $this->aOptionsValues ) ) {
319
+ return;
320
+ }
321
+ foreach( $this->aOptionsValues as $sKey => $mValue ) {
322
+ if ( !$this->getIsValidOptionKey( $sKey ) ) {
323
+ $this->setNeedSave( true );
324
+ unset( $this->aOptionsValues[$sKey] );
325
+ }
326
+ }
327
+ }
328
+
329
+ /**
330
+ * @param boolean $fReload
331
+ * @return array
332
+ * @throws Exception
333
+ */
334
+ private function loadOptionsValuesFromStorage( $fReload = false ) {
335
+
336
+ if ( $fReload || empty( $this->aOptionsValues ) ) {
337
+
338
+ $sStorageKey = $this->getOptionsStorageKey();
339
+ if ( empty( $sStorageKey ) ) {
340
+ throw new Exception( 'Options Storage Key Is Empty' );
341
+ }
342
+
343
+ $oWpFunc = $this->loadWpFunctionsProcessor();
344
+ $this->aOptionsValues = $oWpFunc->getOption( $sStorageKey, array() );
345
+ if ( empty( $this->aOptionsValues ) ) {
346
+ $this->aOptionsValues = array();
347
+ $this->setNeedSave( true );
348
+ }
349
+ }
350
+ return $this->aOptionsValues;
351
+ }
352
+
353
+ /**
354
+ * @param string $sName
355
+ * @return array
356
+ * @throws Exception
357
+ */
358
+ private function readYamlConfiguration( $sName ) {
359
+ $oFs = $this->loadFileSystemProcessor();
360
+
361
+ $aConfig = array();
362
+ $sConfigFile = dirname( __FILE__ ). sprintf( ICWP_DS.'config'.ICWP_DS.'feature-%s.txt', $sName );
363
+ $sContents = $oFs->getFileContent( $sConfigFile );
364
+ if ( !empty( $sContents ) ) {
365
+ $oYaml = $this->loadYamlProcessor();
366
+ $aConfig = $oYaml->parseYamlString( $sContents );
367
+ if ( is_null( $aConfig ) ) {
368
+ throw new Exception( 'YAML parser could not load to process the options configuration.' );
369
+ }
370
+ }
371
+ return $aConfig;
372
+ }
373
+ }
src/icwp-optionshandler-admin_access_restriction.php CHANGED
@@ -21,16 +21,6 @@ if ( !class_exists('ICWP_WPSF_FeatureHandler_AdminAccessRestriction') ):
21
 
22
  class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
- /**
25
- * @const integer
26
- */
27
- const Default_AccessKeyTimeout = 30;
28
-
29
- /**
30
- * @var string
31
- */
32
- const AdminAccessKeyCookieName = 'icwp_wpsf_aakcook';
33
-
34
  private $fHasPermissionToSubmit;
35
 
36
  /**
@@ -41,7 +31,6 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
41
  public function __construct( $oPluginVo ) {
42
  $this->sFeatureName = _wpsf__('Admin Access');
43
  $this->sFeatureSlug = 'admin_access_restriction';
44
- $this->fShowFeatureMenuItem = true;
45
  parent::__construct( $oPluginVo );
46
 
47
  add_filter( $this->doPluginPrefix( 'has_permission_to_submit' ), array( $this, 'doCheckHasPermissionToSubmit' ) );
@@ -53,135 +42,183 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
53
  */
54
  protected function loadFeatureProcessor() {
55
  if ( !isset( $this->oFeatureProcessor ) ) {
56
- require_once( dirname(__FILE__).'/icwp-processor-adminaccessrestriction.php' );
57
  $this->oFeatureProcessor = new ICWP_WPSF_Processor_AdminAccessRestriction( $this );
58
  }
59
  return $this->oFeatureProcessor;
60
  }
61
 
62
  /**
63
- *
 
64
  */
65
  public function doCheckHasPermissionToSubmit( $fHasPermission = true ) {
66
 
67
- $this->loadDataProcessor();
68
- $sAccessKeyRequest = ICWP_WPSF_DataProcessor::FetchPost( $this->doPluginPrefix( 'admin_access_key_request', '_' ) );
69
- if ( !empty( $sAccessKeyRequest ) ) {
70
- $sAccessKeyRequest = md5( trim( $sAccessKeyRequest ) );
71
- if ( $sAccessKeyRequest === $this->getOpt( 'admin_access_key' ) ) {
72
- $this->setPermissionToSubmit( true );
73
- wp_safe_redirect( network_admin_url() );
74
- }
75
  }
76
 
77
  if ( isset( $this->fHasPermissionToSubmit ) ) {
78
  return $this->fHasPermissionToSubmit;
79
  }
 
 
 
80
  $this->fHasPermissionToSubmit = $fHasPermission;
81
  if ( $this->getIsMainFeatureEnabled() ) {
 
82
  $sAccessKey = $this->getOpt( 'admin_access_key' );
83
  if ( !empty( $sAccessKey ) ) {
84
- $this->loadDataProcessor();
85
- $sHash = md5( $sAccessKey.ICWP_WPSF_DataProcessor::GetVisitorIpAddress() );
86
- $sCookieValue = ICWP_WPSF_DataProcessor::FetchCookie( self::AdminAccessKeyCookieName );
87
- $this->fHasPermissionToSubmit = $sCookieValue === $sHash;
88
  }
89
  }
90
  return $this->fHasPermissionToSubmit;
91
  }
92
 
93
  /**
94
- *
95
  */
96
- public function handleFormSubmit() {
97
- $fSuccess = parent::handleFormSubmit();
98
- if ( !$fSuccess ) {
99
- return $fSuccess;
 
 
 
100
  }
 
101
 
102
- if ( $this->getIsCurrentPageConfig() && is_null( ICWP_WPSF_DataProcessor::FetchPost( $this->doPluginPrefix( 'enable_admin_access_restriction', '_' ) ) ) ) {
103
- $this->setPermissionToSubmit( false );
 
 
 
 
 
 
 
 
 
 
 
 
104
  }
105
  }
106
 
 
 
 
 
 
 
 
107
  /**
108
  * @param bool $fPermission
109
  */
110
  protected function setPermissionToSubmit( $fPermission = false ) {
111
  if ( $fPermission ) {
112
- $this->loadDataProcessor();
113
- $sValue = md5( $this->getOpt( 'admin_access_key' ).ICWP_WPSF_DataProcessor::GetVisitorIpAddress() );
114
- $sTimeout = $this->getOpt( 'admin_access_timeout' ) * 60;
115
- $_COOKIE[ self::AdminAccessKeyCookieName ] = $sValue;
116
- setcookie( self::AdminAccessKeyCookieName, $sValue, time()+$sTimeout, COOKIEPATH, COOKIE_DOMAIN, false );
117
  }
118
  else {
119
- unset( $_COOKIE[ self::AdminAccessKeyCookieName ] );
120
- setcookie( self::AdminAccessKeyCookieName, "", time()-3600, COOKIEPATH, COOKIE_DOMAIN, false );
121
  }
122
  }
123
 
124
  /**
125
- * @return bool|void
126
  */
127
- protected function getOptionsDefinitions() {
128
-
129
- if ( $this->hasEncryptOption() ) {
130
-
131
- $aAccessKey = array(
132
- 'section_title' => _wpsf__( 'Admin Access Restriction' ),
133
- 'section_options' => array(
134
- array(
135
- 'enable_admin_access_restriction',
136
- '',
137
- 'N',
138
- 'checkbox',
139
- _wpsf__( 'Enable Access Key' ),
140
- _wpsf__( 'Enforce Admin Access Restriction' ),
141
- _wpsf__( 'Enable this with great care and consideration. When this Access Key option is enabled, you must specify a key below and use it to gain access to this plugin.' ),
142
- '<a href="http://icwp.io/40" target="_blank">'._wpsf__( 'more info' ).'</a>'
143
- .' | <a href="http://icwp.io/wpsf02" target="_blank">'._wpsf__( 'blog' ).'</a>'
144
- ),
145
- array(
146
- 'admin_access_key',
147
- '',
148
- '',
149
- 'password',
150
- _wpsf__( 'Admin Access Key' ),
151
- _wpsf__( 'Specify Your Plugin Access Key' ),
152
- _wpsf__( 'If you forget this, you could potentially lock yourself out from using this plugin.' )
153
- .' <strong>'._wpsf__( 'Leave it blank to not update it' ).'</strong>',
154
- '<a href="http://icwp.io/42" target="_blank">'._wpsf__( 'more info' ).'</a>'
155
- ),
156
- array(
157
- 'admin_access_timeout',
158
- '',
159
- self::Default_AccessKeyTimeout,
160
- 'integer',
161
- _wpsf__( 'Access Key Timeout' ),
162
- _wpsf__( 'Specify A Timeout For Plugin Admin Access' ),
163
- _wpsf__( 'This will automatically expire your WordPress Simple Firewall session. Does not apply until you enter the access key again.').'<br />'.sprintf(_wpsf__( 'Default: %s minutes.' ), self::Default_AccessKeyTimeout ),
164
- '<a href="http://icwp.io/41" target="_blank">'._wpsf__( 'more info' ).'</a>'
165
- )
166
- )
167
- );
168
- }
169
- $aOptionsDefinitions = array(
170
- $aAccessKey
171
- );
172
- return $aOptionsDefinitions;
173
  }
174
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  /**
176
  * This is the point where you would want to do any options verification
177
  */
178
  protected function doPrePluginOptionsSave() {
179
-
180
- if ( $this->getOpt( 'admin_access_key_timeout' ) <= 0 ) {
181
- $this->setOpt( 'admin_access_key_timeout', self::Default_AccessKeyTimeout );
182
  }
183
-
184
- $sAccessKey = $this->getOpt( 'admin_access_key');
 
 
 
 
 
185
  if ( empty( $sAccessKey ) ) {
186
  $this->setOpt( 'enable_admin_access_restriction', 'N' );
187
  }
@@ -189,6 +226,11 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
189
 
190
  protected function updateHandler() {
191
  parent::updateHandler();
 
 
 
 
 
192
  if ( version_compare( $this->getVersion(), '3.0.0', '<' ) ) {
193
  $aAllOptions = apply_filters( $this->doPluginPrefix( 'aggregate_all_plugin_options' ), array() );
194
  $this->setOpt( 'enable_admin_access_restriction', $aAllOptions['enable_admin_access_restriction'] );
21
 
22
  class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureHandler_Base {
23
 
 
 
 
 
 
 
 
 
 
 
24
  private $fHasPermissionToSubmit;
25
 
26
  /**
31
  public function __construct( $oPluginVo ) {
32
  $this->sFeatureName = _wpsf__('Admin Access');
33
  $this->sFeatureSlug = 'admin_access_restriction';
 
34
  parent::__construct( $oPluginVo );
35
 
36
  add_filter( $this->doPluginPrefix( 'has_permission_to_submit' ), array( $this, 'doCheckHasPermissionToSubmit' ) );
42
  */
43
  protected function loadFeatureProcessor() {
44
  if ( !isset( $this->oFeatureProcessor ) ) {
45
+ require_once( $this->getController()->getSourceDir( sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) ) );
46
  $this->oFeatureProcessor = new ICWP_WPSF_Processor_AdminAccessRestriction( $this );
47
  }
48
  return $this->oFeatureProcessor;
49
  }
50
 
51
  /**
52
+ * @param bool $fHasPermission
53
+ * @return bool
54
  */
55
  public function doCheckHasPermissionToSubmit( $fHasPermission = true ) {
56
 
57
+ // We don't use setPermissionToSubmit() here because of timing with headers - we just for now manually
58
+ // checking POST for the submission of the key and if it fits, we say "yes"
59
+ if ( $this->checkAdminAccessKeySubmission() ) {
60
+ $this->fHasPermissionToSubmit = true;
 
 
 
 
61
  }
62
 
63
  if ( isset( $this->fHasPermissionToSubmit ) ) {
64
  return $this->fHasPermissionToSubmit;
65
  }
66
+
67
+ $oDp = $this->loadDataProcessor();
68
+
69
  $this->fHasPermissionToSubmit = $fHasPermission;
70
  if ( $this->getIsMainFeatureEnabled() ) {
71
+
72
  $sAccessKey = $this->getOpt( 'admin_access_key' );
73
  if ( !empty( $sAccessKey ) ) {
74
+ $sHash = md5( $sAccessKey );
75
+ $sCookieValue = $oDp->FetchCookie( $this->getAdminAccessKeyCookieName() );
76
+ $this->fHasPermissionToSubmit = ( $sCookieValue === $sHash );
 
77
  }
78
  }
79
  return $this->fHasPermissionToSubmit;
80
  }
81
 
82
  /**
 
83
  */
84
+ protected function setAdminAccessCookie() {
85
+ $sAccessKey = $this->getOpt( 'admin_access_key' );
86
+ if ( !empty( $sAccessKey ) ) {
87
+ $sValue = md5( $sAccessKey );
88
+ $sTimeout = $this->getOpt( 'admin_access_timeout' ) * 60;
89
+ $_COOKIE[ $this->getAdminAccessKeyCookieName() ] = $sValue;
90
+ setcookie( $this->getAdminAccessKeyCookieName(), $sValue, time()+$sTimeout, COOKIEPATH, COOKIE_DOMAIN, false );
91
  }
92
+ }
93
 
94
+ /**
95
+ */
96
+ protected function clearAdminAccessCookie() {
97
+ unset( $_COOKIE[ $this->getAdminAccessKeyCookieName() ] );
98
+ setcookie( $this->getAdminAccessKeyCookieName(), "", time()-3600, COOKIEPATH, COOKIE_DOMAIN, false );
99
+ }
100
+
101
+ /**
102
+ */
103
+ protected function doExtraSubmitProcessing() {
104
+ // We should only use setPermissionToSubmit() here, before any headers elsewhere are sent out.
105
+ if ( $this->checkAdminAccessKeySubmission() ) {
106
+ $this->setPermissionToSubmit( true );
107
+ wp_safe_redirect( network_admin_url() );
108
  }
109
  }
110
 
111
+ /**
112
+ * @return string
113
+ */
114
+ public function getAdminAccessKeyCookieName() {
115
+ return $this->getOpt( 'admin_access_key_cookie_name' );
116
+ }
117
+
118
  /**
119
  * @param bool $fPermission
120
  */
121
  protected function setPermissionToSubmit( $fPermission = false ) {
122
  if ( $fPermission ) {
123
+ $this->setAdminAccessCookie();
 
 
 
 
124
  }
125
  else {
126
+ $this->clearAdminAccessCookie();
 
127
  }
128
  }
129
 
130
  /**
131
+ * @return bool
132
  */
133
+ protected function checkAdminAccessKeySubmission() {
134
+ $oDp = $this->loadDataProcessor();
135
+
136
+ $sAccessKeyRequest = $oDp->FetchPost( $this->doPluginPrefix( 'admin_access_key_request', '_' ) );
137
+ if ( empty( $sAccessKeyRequest ) ) {
138
+ return false;
139
+ }
140
+ return $this->getOpt( 'admin_access_key' ) === md5( $sAccessKeyRequest );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  }
142
+
143
+ /**
144
+ * @param array $aOptionsParams
145
+ * @return array
146
+ * @throws Exception
147
+ */
148
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
149
+
150
+ $sSectionSlug = $aOptionsParams['section_slug'];
151
+ switch( $aOptionsParams['section_slug'] ) {
152
+
153
+ case 'section_enable_plugin_feature_admin_access_restriction' :
154
+ $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('Admin Access Restriction') );
155
+ break;
156
+
157
+ case 'section_admin_access_restriction_settings' :
158
+ $sTitle = _wpsf__( 'Admin Access Restriction Settings' );
159
+ break;
160
+
161
+ default:
162
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
163
+ }
164
+ $aOptionsParams['section_title'] = $sTitle;
165
+ return $aOptionsParams;
166
+ }
167
+
168
+ /**
169
+ * @param array $aOptionsParams
170
+ * @return array
171
+ * @throws Exception
172
+ */
173
+ protected function loadStrings_Options( $aOptionsParams ) {
174
+
175
+ $sKey = $aOptionsParams['key'];
176
+ switch( $sKey ) {
177
+
178
+ case 'enable_admin_access_restriction' :
179
+ $sName = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('Admin Access') );
180
+ $sSummary = _wpsf__( 'Enforce Admin Access Restriction' );
181
+ $sDescription = _wpsf__( 'Enable this with great care and consideration. When this Access Key option is enabled, you must specify a key below and use it to gain access to this plugin.' );
182
+ break;
183
+
184
+ case 'admin_access_key' :
185
+ $sName = _wpsf__( 'Admin Access Key' );
186
+ $sSummary = _wpsf__( 'Provide/Update Admin Access Key' );
187
+ $sDescription = sprintf( _wpsf__( 'Careful: %s' ), _wpsf__( 'If you forget this, you could potentially lock yourself out from using this plugin.' ) );
188
+ break;
189
+
190
+ case 'admin_access_timeout' :
191
+ $sName = _wpsf__( 'Admin Access Timeout' );
192
+ $sSummary = _wpsf__( 'Specify An Automatic Timeout Interval For Admin Access' );
193
+ $sDescription = _wpsf__( 'This will automatically expire your WordPress Simple Firewall session. Does not apply until you enter the access key again.')
194
+ .'<br />'.sprintf( _wpsf__( 'Default: %s minutes.' ), $this->getOptionsVo()->getOptDefault( 'admin_access_timeout' ) );
195
+ break;
196
+
197
+ default:
198
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
199
+ }
200
+
201
+ $aOptionsParams['name'] = $sName;
202
+ $aOptionsParams['summary'] = $sSummary;
203
+ $aOptionsParams['description'] = $sDescription;
204
+ return $aOptionsParams;
205
+ }
206
+
207
  /**
208
  * This is the point where you would want to do any options verification
209
  */
210
  protected function doPrePluginOptionsSave() {
211
+
212
+ if ( $this->getOpt( 'admin_access_timeout' ) < 1 ) {
213
+ $this->getOptionsVo()->resetOptToDefault( 'admin_access_timeout' );
214
  }
215
+
216
+ $sNotificationEmail = $this->getOpt( 'enable_admin_login_email_notification' );
217
+ if ( !empty( $sNotificationEmail ) && !is_email( $sNotificationEmail ) ) {
218
+ $this->setOpt( 'enable_admin_login_email_notification', '' );
219
+ }
220
+
221
+ $sAccessKey = $this->getOpt( 'admin_access_key' );
222
  if ( empty( $sAccessKey ) ) {
223
  $this->setOpt( 'enable_admin_access_restriction', 'N' );
224
  }
226
 
227
  protected function updateHandler() {
228
  parent::updateHandler();
229
+
230
+ if ( $this->getVersion() == '0.0' ) {
231
+ return;
232
+ }
233
+
234
  if ( version_compare( $this->getVersion(), '3.0.0', '<' ) ) {
235
  $aAllOptions = apply_filters( $this->doPluginPrefix( 'aggregate_all_plugin_options' ), array() );
236
  $this->setOpt( 'enable_admin_access_restriction', $aAllOptions['enable_admin_access_restriction'] );
src/icwp-optionshandler-audit_trail.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_FeatureHandler_AuditTrail_V1') ):
21
+
22
+ class ICWP_WPSF_FeatureHandler_AuditTrail_V1 extends ICWP_WPSF_FeatureHandler_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_Processor_AuditTrail
26
+ */
27
+ protected $oFeatureProcessor;
28
+
29
+ public function __construct( $oPluginVo ) {
30
+ $this->sFeatureName = _wpsf__('Audit Trail');
31
+ $this->sFeatureSlug = 'audit_trail';
32
+ parent::__construct( $oPluginVo );
33
+ }
34
+
35
+ /**
36
+ * @return ICWP_WPSF_Processor_Autoupdates|null
37
+ */
38
+ protected function loadFeatureProcessor() {
39
+ if ( !isset( $this->oFeatureProcessor ) ) {
40
+ require_once( $this->getController()->getSourceDir( sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) ) );
41
+ $this->oFeatureProcessor = new ICWP_WPSF_Processor_AuditTrail( $this );
42
+ }
43
+ return $this->oFeatureProcessor;
44
+ }
45
+
46
+ /**
47
+ * @return bool|void
48
+ */
49
+ public function doExtraSubmitProcessing() { }
50
+
51
+ public function doPrePluginOptionsSave() {}
52
+
53
+ /**
54
+ * @return string
55
+ */
56
+ public function getAuditTrailTableName() {
57
+ return $this->doPluginPrefix( $this->getOpt( 'audit_trail_table_name' ), '_' );
58
+ }
59
+
60
+ /**
61
+ * @param array $aOptionsParams
62
+ * @return array
63
+ * @throws Exception
64
+ */
65
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
66
+
67
+ $sSectionSlug = $aOptionsParams['section_slug'];
68
+ switch( $sSectionSlug ) {
69
+
70
+ case 'section_enable_plugin_feature_audit_trail' :
71
+ $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), $this->getMainFeatureName() );
72
+ break;
73
+
74
+ case 'section_enable_audit_contexts' :
75
+ $sTitle = _wpsf__( 'Enable Audit Contexts' );
76
+ break;
77
+
78
+ default:
79
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
80
+ }
81
+ $aOptionsParams['section_title'] = $sTitle;
82
+ return $aOptionsParams;
83
+ }
84
+
85
+ /**
86
+ * @param array $aOptionsParams
87
+ * @return array
88
+ * @throws Exception
89
+ */
90
+ protected function loadStrings_Options( $aOptionsParams ) {
91
+
92
+ $sKey = $aOptionsParams['key'];
93
+ switch( $sKey ) {
94
+
95
+ case 'enable_audit_trail' :
96
+ $sName = sprintf( _wpsf__( 'Enable %s' ), $this->getMainFeatureName() );
97
+ $sSummary = sprintf( _wpsf__( 'Enable (or Disable) The %s Feature' ), $this->getMainFeatureName() );
98
+ $sDescription = sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), $this->getMainFeatureName() );
99
+ break;
100
+
101
+ case 'enable_audit_context_users' :
102
+ $sName = _wpsf__( 'Users And Logins' );
103
+ $sSummary = sprintf( _wpsf__( 'Enable Audit Context - %s' ), _wpsf__( 'Users And Logins' ) );
104
+ $sDescription = _wpsf__( 'When this context is enabled, the audit trail will track user activity and significant events such as user login etc.' );
105
+ break;
106
+
107
+ case 'enable_audit_context_plugins' :
108
+ $sName = _wpsf__( 'Plugins' );
109
+ $sSummary = sprintf( _wpsf__( 'Enable Audit Context - %s' ), _wpsf__( 'Plugins' ) );
110
+ $sDescription = _wpsf__( 'When this context is enabled, the audit trail will track user activity and significant events such as user login etc.' );
111
+ break;
112
+
113
+ case 'enable_audit_context_themes' :
114
+ $sName = _wpsf__( 'Themes' );
115
+ $sSummary = sprintf( _wpsf__( 'Enable Audit Context - %s' ), _wpsf__( 'Themes' ) );
116
+ $sDescription = _wpsf__( 'When this context is enabled, the audit trail will track user activity and significant events such as user login etc.' );
117
+ break;
118
+
119
+ case 'enable_audit_context_posts' :
120
+ $sName = _wpsf__( 'Posts And Pages' );
121
+ $sSummary = sprintf( _wpsf__( 'Enable Audit Context - %s' ), _wpsf__( 'Posts And Pages' ) );
122
+ $sDescription = _wpsf__( 'When this context is enabled, the audit trail will track user activity and significant events such as user login etc.' );
123
+ break;
124
+
125
+ case 'enable_audit_context_wordpress' :
126
+ $sName = _wpsf__( 'WordPress And Settings' );
127
+ $sSummary = sprintf( _wpsf__( 'Enable Audit Context - %s' ), _wpsf__( 'WordPress And Settings' ) );
128
+ $sDescription = _wpsf__( 'When this context is enabled, the audit trail will track user activity and significant events such as user login etc.' );
129
+ break;
130
+
131
+ case 'enable_audit_context_wpsf' :
132
+ $sName = _wpsf__( 'Simple Firewall' );
133
+ $sSummary = sprintf( _wpsf__( 'Enable Audit Context - %s' ), _wpsf__( 'Simple Firewall' ) );
134
+ $sDescription = _wpsf__( 'When this context is enabled, the audit trail will track user activity and significant events such as user login etc.' );
135
+ break;
136
+
137
+ default:
138
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
139
+ }
140
+
141
+ $aOptionsParams['name'] = $sName;
142
+ $aOptionsParams['summary'] = $sSummary;
143
+ $aOptionsParams['description'] = $sDescription;
144
+ return $aOptionsParams;
145
+ }
146
+ }
147
+
148
+ endif;
149
+
150
+ class ICWP_WPSF_FeatureHandler_AuditTrail extends ICWP_WPSF_FeatureHandler_AuditTrail_V1 { }
src/icwp-optionshandler-autoupdates.php CHANGED
@@ -17,193 +17,163 @@
17
 
18
  require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
19
 
20
- if ( !class_exists('ICWP_WPSF_FeatureHandler_Autoupdates_V2') ):
21
 
22
- class ICWP_WPSF_FeatureHandler_Autoupdates_V2 extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
- /**
25
- * @var ICWP_WPSF_AutoupdatesProcessor
26
- */
27
- protected $oFeatureProcessor;
28
 
29
- public function __construct( $oPluginVo ) {
30
- $this->sFeatureName = _wpsf__('Automatic Updates');
31
- $this->sFeatureSlug = 'autoupdates';
32
- parent::__construct( $oPluginVo );
33
- }
34
 
35
- /**
36
- * @return ICWP_WPSF_AutoupdatesProcessor|null
37
- */
38
- protected function loadFeatureProcessor() {
39
- if ( !isset( $this->oFeatureProcessor ) ) {
40
- require_once( dirname(__FILE__).'/icwp-processor-autoupdates.php' );
41
- $this->oFeatureProcessor = new ICWP_WPSF_AutoupdatesProcessor( $this );
 
 
42
  }
43
- return $this->oFeatureProcessor;
44
- }
45
 
46
- /**
47
- * @return bool|void
48
- */
49
- public function handleFormSubmit() {
50
- $fSuccess = parent::handleFormSubmit();
51
- if ( !$fSuccess ) {
52
- return $fSuccess;
 
 
 
 
53
  }
54
 
55
- // Force run automatic updates
56
- $this->loadDataProcessor();
57
- if ( ICWP_WPSF_DataProcessor::FetchGet( 'force_run_auto_updates' ) == 'now' ) {
58
- $oProc = $this->getProcessor();
59
- $oProc->setForceRunAutoupdates( true );
60
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
62
- }
63
 
64
- public function doPrePluginOptionsSave() {}
65
-
66
- /**
67
- * @return array
68
- */
69
- protected function getOptionsDefinitions() {
70
- $aAutoupdatesBase = array(
71
- 'section_title' => _wpsf__('Enable Automatic Updates Section'),
72
- 'section_options' => array(
73
- array(
74
- 'enable_autoupdates',
75
- '',
76
- 'Y',
77
- 'checkbox',
78
- _wpsf__( 'Enable Auto Updates' ),
79
- _wpsf__( 'Enable (or Disable) The Simple Firewall Automatic Updates Feature' ),
80
- sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('Automatic Updates') ),
81
- '<a href="http://icwp.io/3w" target="_blank">'._wpsf__( 'more info' ).'</a>'
82
- )
83
- )
84
- );
85
- $aAutoupdateAll = array(
86
- 'section_title' => _wpsf__('Disable ALL WordPress Automatic Updates'),
87
- 'section_options' => array(
88
- array(
89
- 'enable_autoupdate_disable_all',
90
- '',
91
- 'N',
92
- 'checkbox',
93
- _wpsf__( 'Disable All' ),
94
- _wpsf__( 'Completely Disable WordPress Automatic Updates' ),
95
- _wpsf__( 'When selected, regardless of any other settings, all WordPress automatic updates on this site will be completely disabled!' ),
96
- '<a href="http://icwp.io/3v" target="_blank">'._wpsf__( 'more info' ).'</a>'
97
- )
98
- )
99
- );
100
- $aAutoupdatePlugin = array(
101
- 'section_title' => _wpsf__('Automatic Plugin Self-Update'),
102
- 'section_options' => array(
103
- array(
104
- 'autoupdate_plugin_self',
105
- '',
106
- 'Y',
107
- 'checkbox',
108
- _wpsf__( 'Auto Update Plugin' ),
109
- _wpsf__( 'Always Automatically Update This Plugin' ),
110
- _wpsf__( 'Regardless of any component settings below, automatically update the WordPress Simple Firewall plugin.' ),
111
- '<a href="http://icwp.io/3u" target="_blank">'._wpsf__( 'more info' ).'</a>'
112
- )
113
- )
114
- );
115
- $aAutoupdateOptions = array( 'select',
116
- array( 'core_never', _wpsf__('Never') ),
117
- array( 'core_minor', _wpsf__('Minor Versions Only') ),
118
- array( 'core_major', _wpsf__('Major and Minor Versions') ),
119
- );
120
- $aAutoupdateComponents = array(
121
- 'section_title' => _wpsf__('Choose Which WordPress Components To Allow Automatic Updates'),
122
- 'section_options' => array(
123
- array(
124
- 'autoupdate_core',
125
- '',
126
- 'core_minor',
127
- $aAutoupdateOptions,
128
- _wpsf__( 'WordPress Core Updates' ),
129
- _wpsf__( 'Decide how the WordPress Core will automatically update, if at all' ),
130
- _wpsf__( 'At least automatically upgrading minor versions is recommended (and is the WordPress default).' ),
131
- '<a href="http://icwp.io/3x" target="_blank">'._wpsf__( 'more info' ).'</a>'
132
- ),
133
- array(
134
- 'enable_autoupdate_translations',
135
- '',
136
- 'Y',
137
- 'checkbox',
138
- _wpsf__( 'Translations' ),
139
- _wpsf__( 'Automatically Update Translations' ),
140
- _wpsf__( 'Note: Automatic updates for translations are enabled on WordPress by default.' )
141
- ),
142
- array(
143
- 'enable_autoupdate_plugins',
144
- '',
145
- 'N',
146
- 'checkbox',
147
- _wpsf__( 'Plugins' ),
148
- _wpsf__( 'Automatically Update Plugins' ),
149
- _wpsf__( 'Note: Automatic updates for plugins are disabled on WordPress by default.' )
150
- ),
151
- array(
152
- 'enable_autoupdate_themes',
153
- '',
154
- 'N',
155
- 'checkbox',
156
- _wpsf__( 'Themes' ),
157
- _wpsf__( 'Automatically Update Themes' ),
158
- _wpsf__( 'Note: Automatic updates for themes are disabled on WordPress by default.' )
159
- ),
160
- array(
161
- 'enable_autoupdate_ignore_vcs',
162
- '',
163
- 'N',
164
- 'checkbox',
165
- _wpsf__( 'Ignore Version Control' ),
166
- _wpsf__( 'Ignore Version Control Systems Such As GIT and SVN' ),
167
- _wpsf__( 'If you use SVN or GIT and WordPress detects it, automatic updates are disabled by default. Check this box to ignore version control systems and allow automatic updates.' )
168
- )
169
- )
170
- );
171
-
172
- $aAutoupdateEmail = array(
173
- 'section_title' => _wpsf__('Automatic Update Email Notifications'),
174
- 'section_options' => array(
175
- array(
176
- 'enable_upgrade_notification_email',
177
- '',
178
- 'Y',
179
- 'checkbox',
180
- _wpsf__( 'Send Report Email' ),
181
- _wpsf__( 'Send email notices after automatic updates' ),
182
- _wpsf__( 'You can turn on/off email notices from automatic updates by un/checking this box.' )
183
- ),
184
- array(
185
- 'override_email_address',
186
- '',
187
- '',
188
- 'email',
189
- _wpsf__( 'Report Email Address' ),
190
- _wpsf__( 'Where to send upgrade notification reports' ),
191
- _wpsf__( 'If this is empty, it will default to the Site admin email address' )
192
- )
193
- )
194
- );
195
-
196
- $aOptionsDefinitions = array(
197
- $aAutoupdatesBase,
198
- $aAutoupdateAll,
199
- $aAutoupdatePlugin,
200
- $aAutoupdateComponents,
201
- $aAutoupdateEmail
202
- );
203
- return $aOptionsDefinitions;
204
  }
205
- }
206
 
207
  endif;
208
 
209
- class ICWP_WPSF_FeatureHandler_Autoupdates extends ICWP_WPSF_FeatureHandler_Autoupdates_V2 { }
17
 
18
  require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
19
 
20
+ if ( !class_exists('ICWP_WPSF_FeatureHandler_Autoupdates_V3') ):
21
 
22
+ class ICWP_WPSF_FeatureHandler_Autoupdates_V3 extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
+ /**
25
+ * @var ICWP_WPSF_Processor_Autoupdates
26
+ */
27
+ protected $oFeatureProcessor;
28
 
29
+ public function __construct( $oPluginVo ) {
30
+ $this->sFeatureName = _wpsf__('Automatic Updates');
31
+ $this->sFeatureSlug = 'autoupdates';
32
+ parent::__construct( $oPluginVo );
33
+ }
34
 
35
+ /**
36
+ * @return ICWP_WPSF_Processor_Autoupdates|null
37
+ */
38
+ protected function loadFeatureProcessor() {
39
+ if ( !isset( $this->oFeatureProcessor ) ) {
40
+ require_once( $this->getController()->getSourceDir( sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) ) );
41
+ $this->oFeatureProcessor = new ICWP_WPSF_Processor_Autoupdates( $this );
42
+ }
43
+ return $this->oFeatureProcessor;
44
  }
 
 
45
 
46
+ /**
47
+ * @return bool|void
48
+ */
49
+ protected function doExtraSubmitProcessing() {
50
+ // Force run automatic updates
51
+ $oDp = $this->loadDataProcessor();
52
+ if ( $oDp->FetchGet( 'force_run_auto_updates' ) == 'now' ) {
53
+ $oProc = $this->getProcessor();
54
+ $oProc->setForceRunAutoupdates( true );
55
+ return;
56
+ }
57
  }
58
 
59
+ /**
60
+ * @param array $aOptionsParams
61
+ * @return array
62
+ * @throws Exception
63
+ */
64
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
65
+
66
+ $sSectionSlug = $aOptionsParams['section_slug'];
67
+ switch( $sSectionSlug ) {
68
+
69
+ case 'section_enable_plugin_feature_automatic_updates_control' :
70
+ $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), $this->getMainFeatureName() );
71
+ break;
72
+
73
+ case 'section_disable_all_wordpress_automatic_updates' :
74
+ $sTitle = _wpsf__('Disable ALL WordPress Automatic Updates');
75
+ break;
76
+
77
+ case 'section_automatic_plugin_self_update' :
78
+ $sTitle = _wpsf__('Automatic Plugin Self-Update');
79
+ break;
80
+
81
+ case 'section_automatic_updates_for_wordpress_components' :
82
+ $sTitle = _wpsf__('Automatic Updates For WordPress Components');
83
+ break;
84
+
85
+ case 'section_automatic_update_email_notifications' :
86
+ $sTitle = _wpsf__('Automatic Update Email Notifications');
87
+ break;
88
+
89
+ default:
90
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
91
+ }
92
+ $aOptionsParams['section_title'] = $sTitle;
93
+ return $aOptionsParams;
94
  }
 
95
 
96
+ /**
97
+ * @param array $aOptionsParams
98
+ * @return array
99
+ * @throws Exception
100
+ */
101
+ protected function loadStrings_Options( $aOptionsParams ) {
102
+
103
+ $sKey = $aOptionsParams['key'];
104
+ switch( $sKey ) {
105
+
106
+ case 'enable_autoupdates' :
107
+ $sName = sprintf( _wpsf__( 'Enable %s' ), $this->getMainFeatureName() );
108
+ $sSummary = sprintf( _wpsf__( 'Enable (or Disable) The %s Feature' ), $this->getMainFeatureName() );
109
+ $sDescription = sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), $this->getMainFeatureName() );
110
+ break;
111
+
112
+ case 'enable_autoupdate_disable_all' :
113
+ $sName = _wpsf__( 'Disable All' );
114
+ $sSummary = _wpsf__( 'Completely Disable WordPress Automatic Updates' );
115
+ $sDescription = _wpsf__( 'When selected, regardless of any other settings, all WordPress automatic updates on this site will be completely disabled!' );
116
+ break;
117
+
118
+ case 'autoupdate_plugin_self' :
119
+ $sName = _wpsf__( 'Auto Update Plugin' );
120
+ $sSummary = _wpsf__( 'Always Automatically Update This Plugin' );
121
+ $sDescription = _wpsf__( 'Regardless of any component settings below, automatically update the WordPress Simple Firewall plugin.' );
122
+ break;
123
+
124
+ case 'autoupdate_core' :
125
+ $sName = _wpsf__( 'WordPress Core Updates' );
126
+ $sSummary = _wpsf__( 'Decide how the WordPress Core will automatically update, if at all' );
127
+ $sDescription = _wpsf__( 'At least automatically upgrading minor versions is recommended (and is the WordPress default).' );
128
+ break;
129
+
130
+ case 'enable_autoupdate_translations' :
131
+ $sName = _wpsf__( 'Translations' );
132
+ $sSummary = _wpsf__( 'Automatically Update Translations' );
133
+ $sDescription = _wpsf__( 'Note: Automatic updates for translations are enabled on WordPress by default.' );
134
+ break;
135
+
136
+ case 'enable_autoupdate_plugins' :
137
+ $sName = _wpsf__( 'Plugins' );
138
+ $sSummary = _wpsf__( 'Automatically Update Plugins' );
139
+ $sDescription = _wpsf__( 'Note: Automatic updates for plugins are disabled on WordPress by default.' );
140
+ break;
141
+
142
+ case 'enable_autoupdate_themes' :
143
+ $sName = _wpsf__( 'Themes' );
144
+ $sSummary = _wpsf__( 'Automatically Update Themes' );
145
+ $sDescription = _wpsf__( 'Note: Automatic updates for themes are disabled on WordPress by default.' );
146
+ break;
147
+
148
+ case 'enable_autoupdate_ignore_vcs' :
149
+ $sName = _wpsf__( 'Ignore Version Control' );
150
+ $sSummary = _wpsf__( 'Ignore Version Control Systems Such As GIT and SVN' );
151
+ $sDescription = _wpsf__( 'If you use SVN or GIT and WordPress detects it, automatic updates are disabled by default. Check this box to ignore version control systems and allow automatic updates.' );
152
+ break;
153
+
154
+ case 'enable_upgrade_notification_email' :
155
+ $sName = _wpsf__( 'Send Report Email' );
156
+ $sSummary = _wpsf__( 'Send email notices after automatic updates' );
157
+ $sDescription = _wpsf__( 'You can turn on/off email notices from automatic updates by un/checking this box.' );
158
+ break;
159
+
160
+ case 'override_email_address' :
161
+ $sName = _wpsf__( 'Report Email Address' );
162
+ $sSummary = _wpsf__( 'Where to send upgrade notification reports' );
163
+ $sDescription = _wpsf__( 'If this is empty, it will default to the Site Admin email address' );
164
+ break;
165
+
166
+ default:
167
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
168
+ }
169
+
170
+ $aOptionsParams['name'] = $sName;
171
+ $aOptionsParams['summary'] = $sSummary;
172
+ $aOptionsParams['description'] = $sDescription;
173
+ return $aOptionsParams;
174
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  }
 
176
 
177
  endif;
178
 
179
+ class ICWP_WPSF_FeatureHandler_Autoupdates extends ICWP_WPSF_FeatureHandler_Autoupdates_V3 { }
src/icwp-optionshandler-base.php CHANGED
@@ -3,8 +3,6 @@
3
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
- * Version: 2013-11-15-V1
7
- *
8
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
9
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -17,985 +15,888 @@
17
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
  */
19
 
 
20
  if ( !class_exists('ICWP_WPSF_FeatureHandler_Base_V2') ):
21
 
22
- class ICWP_WPSF_FeatureHandler_Base_V2 {
23
-
24
- /**
25
- * @var ICWP_Wordpress_Simple_Firewall_Plugin
26
- */
27
- protected $oPluginVo;
28
-
29
- /**
30
- * @var string
31
- */
32
- const CollateSeparator = '--SEP--';
33
- /**
34
- * @var string
35
- */
36
- const PluginVersionKey = 'current_plugin_version';
37
-
38
- /**
39
- * @var boolean
40
- */
41
- protected $fNeedSave;
42
-
43
- /**
44
- * @var array
45
- */
46
- protected $aOptions;
47
-
48
- /**
49
- * These are options that need to be stored, but are never set by the UI.
50
- *
51
- * @var array
52
- */
53
- protected $aNonUiOptions;
54
-
55
- /**
56
- * @var array
57
- */
58
- protected $m_aOptionsValues;
59
-
60
- /**
61
- * @var string
62
- */
63
- protected $sOptionsStoreKey;
64
-
65
- /**
66
- * @var array
67
- */
68
- protected $aOptionsKeys;
69
-
70
- /**
71
- * @var string
72
- */
73
- protected $sFeatureName;
74
- /**
75
- * @var string
76
- */
77
- protected $sFeatureSlug;
78
-
79
- /**
80
- * @var string
81
- */
82
- protected static $sPluginBaseFile;
83
-
84
- /**
85
- * @var string
86
- */
87
- protected $fShowFeatureMenuItem = true;
88
-
89
- /**
90
- * @var ICWP_WPSF_FeatureHandler_Email
91
- */
92
- protected static $oEmailHandler;
93
-
94
- /**
95
- * @var ICWP_WPSF_FeatureHandler_Email
96
- */
97
- protected static $oLoggingHandler;
98
-
99
- /**
100
- * @var ICWP_WPSF_BaseProcessor
101
- */
102
- protected $oFeatureProcessor;
103
-
104
- public function __construct( $oPluginVo, $sOptionsStoreKey = null ) {
105
- $this->oPluginVo = $oPluginVo;
106
- $this->sOptionsStoreKey = $this->prefixOptionKey(
107
- ( is_null( $sOptionsStoreKey ) ? $this->getFeatureSlug() : $sOptionsStoreKey )
108
- .'_options'
109
- );
110
-
111
- // Handle any upgrades as necessary (only go near this if it's the admin area)
112
- add_action( 'plugins_loaded', array( $this, 'onWpPluginsLoaded' ) );
113
- add_action( 'init', array( $this, 'onWpInit' ), 1 );
114
- add_action( $this->doPluginPrefix( 'form_submit' ), array( $this, 'handleFormSubmit' ) );
115
- add_filter( $this->doPluginPrefix( 'filter_plugin_submenu_items' ), array( $this, 'filter_addPluginSubMenuItem' ) );
116
- add_filter( $this->doPluginPrefix( 'get_feature_summary_data' ), array( $this, 'filter_getFeatureSummaryData' ) );
117
- add_filter( $this->doPluginPrefix( 'flush_logs' ), array( $this, 'filter_flushFeatureLogs' ) );
118
- add_action( $this->doPluginPrefix( 'plugin_shutdown' ), array( $this, 'action_doFeatureShutdown' ) );
119
-
120
- add_action( $this->doPluginPrefix( 'delete_plugin_options' ), array( $this, 'deletePluginOptions' ) );
121
- add_filter( $this->doPluginPrefix( 'aggregate_all_plugin_options' ), array( $this, 'aggregateOptionsValues' ) );
122
- }
123
-
124
- public function override() {
125
-
126
- $oWpFs = $this->loadFileSystemProcessor();
127
- if ( $oWpFs->exists( path_join( $this->oPluginVo->getRootDir(), 'forceOff') ) ) {
128
- $this->setIsMainFeatureEnabled( false );
129
- }
130
- else if ( $oWpFs->exists( path_join( $this->oPluginVo->getRootDir(), 'forceOn') ) ) {
131
- $this->setIsMainFeatureEnabled( true );
132
  }
133
- }
134
-
135
- public function onWpPluginsLoaded() {
136
- $this->load();
137
- }
138
 
139
- /**
140
- * @return bool
141
- */
142
- public function getIsUpgrading() {
143
- return $this->getVersion() != $this->oPluginVo->getVersion();
144
- }
145
-
146
- /**
147
- * Hooked to the plugin's main plugin_shutdown action
148
- */
149
- public function action_doFeatureShutdown() {
150
- $this->savePluginOptions();
151
 
152
- $aLogData = apply_filters( $this->doPluginPrefix( 'flush_logs' ), array() );
153
- $oLoggingProcessor = $this->getLoggingProcessor();
154
- $oLoggingProcessor->addDataToWrite( $aLogData );
155
- $oLoggingProcessor->commitData();
156
- }
157
 
158
- protected function load() {
159
- if ( !$this->getIsMainFeatureEnabled() ) {
160
- return;
 
 
 
 
 
 
161
  }
162
 
163
- $oProcessor = $this->loadFeatureProcessor();
164
- if ( ! ( is_object( $oProcessor ) && $oProcessor instanceof ICWP_WPSF_BaseProcessor ) ) {
165
- return;
 
 
166
  }
167
 
168
- $oProcessor->run();
169
- }
 
 
170
 
171
- /**
172
- * Override this and adapt per feature
173
- * @return null
174
- */
175
- protected function loadFeatureProcessor() {
176
- return null;
177
- }
178
 
179
- /**
180
- * @return ICWP_WPSF_BaseProcessor
181
- */
182
- public function getProcessor() {
183
- return $this->loadFeatureProcessor();
184
- }
185
-
186
- /**
187
- * @return ICWP_WPSF_FeatureHandler_Email
188
- */
189
- public static function GetEmailHandler() {
190
- if ( is_null( self::$oEmailHandler ) ) {
191
- self::$oEmailHandler = new ICWP_WPSF_FeatureHandler_Email( ICWP_Wordpress_Simple_Firewall_Plugin::GetInstance() );
192
  }
193
- return self::$oEmailHandler;
194
- }
195
-
196
- /**
197
- * @return ICWP_WPSF_EmailProcessor
198
- */
199
- public function getEmailProcessor() {
200
- return $this->GetEmailHandler()->getProcessor();
201
- }
202
 
203
- /**
204
- * @return ICWP_WPSF_FeatureHandler_Logging
205
- */
206
- public static function GetLoggingHandler() {
207
- if ( is_null( self::$oLoggingHandler ) ) {
208
- self::$oLoggingHandler = new ICWP_WPSF_FeatureHandler_Logging( ICWP_Wordpress_Simple_Firewall_Plugin::GetInstance() );
 
 
 
209
  }
210
- return self::$oLoggingHandler;
211
- }
212
-
213
- /**
214
- * @return ICWP_WPSF_LoggingProcessor
215
- */
216
- public function getLoggingProcessor() {
217
- return $this->GetLoggingHandler()->getProcessor();
218
- }
219
 
220
- /**
221
- * @param $fEnable
222
- */
223
- public function setIsMainFeatureEnabled( $fEnable ) {
224
- $this->setOpt( 'enable_'.$this->getFeatureSlug(), $fEnable ? 'Y' : 'N' );
225
- }
226
-
227
- /**
228
- * @return mixed
229
- */
230
- public function getIsMainFeatureEnabled() {
231
- $this->override();
232
- return $this->getOpt( 'enable_'.$this->getFeatureSlug() ) == 'Y';
233
- }
234
-
235
- /**
236
- * @return mixed
237
- */
238
- protected function getMainFeatureName() {
239
- return $this->sFeatureName;
240
- }
241
-
242
- /**
243
- * @return string
244
- */
245
- public function getPluginBaseFile() {
246
- if ( !isset( self::$sPluginBaseFile ) ) {
247
- self::$sPluginBaseFile = plugin_basename( $this->oPluginVo->getRootFile() );
248
  }
249
- return self::$sPluginBaseFile;
250
- }
251
 
252
- /**
253
- * @return string
254
- */
255
- public function getFeatureSlug() {
256
- return $this->sFeatureSlug;
257
- }
258
-
259
- /**
260
- * with trailing slash
261
- */
262
- public function getResourcesDir() {
263
- $this->oPluginVo->getRootDir().'resources'.ICWP_DS;
264
- }
265
-
266
- /**
267
- *
268
- */
269
- public function filter_flushFeatureLogs( $aLogs ) {
270
- if ( $this->getIsMainFeatureEnabled() ) {
271
- $aFeatureLogs = $this->getProcessor()->flushLogData();
272
- if ( !empty( $aFeatureLogs ) ) {
273
- $aLogs = array_merge( $aLogs, $aFeatureLogs );
274
  }
 
275
  }
276
- return $aLogs;
277
- }
278
 
279
- /**
280
- * @param array $aItems
281
- * @return array
282
- */
283
- public function filter_addPluginSubMenuItem( $aItems ) {
284
- if ( !$this->fShowFeatureMenuItem || empty( $this->sFeatureName ) ) {
285
- return $aItems;
286
  }
287
- $sMenuPageTitle = $this->oPluginVo->getHumanName().' - '.$this->getMainFeatureName();
288
- $aItems[ $sMenuPageTitle ] = array(
289
- $this->getMainFeatureName(),
290
- $this->sFeatureSlug,
291
- array( $this, 'displayFeatureConfigPage' )
292
- );
293
- return $aItems;
294
- }
295
 
296
- /**
297
- * @param array $aSummaryData
298
- * @return array
299
- */
300
- public function filter_getFeatureSummaryData( $aSummaryData ) {
301
- if ( !$this->fShowFeatureMenuItem ) {
302
- return $aSummaryData;
 
 
303
  }
304
 
305
- $aSummaryData[] = array(
306
- $this->getIsMainFeatureEnabled(),
307
- $this->getMainFeatureName(),
308
- $this->doPluginPrefix( $this->sFeatureSlug )
309
- );
310
-
311
- return $aSummaryData;
312
- }
313
-
314
- /**
315
- * A action added to WordPress 'plugins_loaded' hook
316
- */
317
- public function onWpInit() {
318
- $this->updateHandler();
319
- }
320
-
321
- /**
322
- * @return bool
323
- */
324
- public function hasPluginManageRights() {
325
- if ( !current_user_can( $this->oPluginVo->getBasePermissions() ) ) {
326
- return false;
327
  }
328
 
329
- $oWpFunc = $this->loadWpFunctions();
330
- if ( is_admin() && !$oWpFunc->isMultisite() ) {
331
- return true;
332
- }
333
- else if ( is_network_admin() && $oWpFunc->isMultisite() ) {
334
- return true;
335
  }
336
- return false;
337
- }
338
-
339
- /**
340
- * @return string
341
- */
342
- public function getVersion() {
343
- $sVersion = $this->getOpt( self::PluginVersionKey );
344
- return empty( $sVersion )? '0.0' : $sVersion;
345
- }
346
-
347
- /**
348
- * Gets the array of all possible options keys
349
- *
350
- * @return array
351
- */
352
- public function getOptionsKeys() {
353
- $this->setOptionsKeys();
354
- return $this->aOptionsKeys;
355
- }
356
 
357
- /**
358
- * @return void
359
- */
360
- public function setOptionsKeys() {
361
- if ( !empty( $this->aOptionsKeys ) ) {
362
- return;
 
 
 
363
  }
364
- $this->buildOptions();
365
- }
366
 
367
- /**
368
- * Determines whether the given option key is a valid option
369
- *
370
- * @param string
371
- * @return boolean
372
- */
373
- public function getIsOptionKey( $sOptionKey ) {
374
- $this->setOptionsKeys();
375
- return ( in_array( $sOptionKey, $this->aOptionsKeys ) );
376
- }
377
 
378
- /**
379
- * Sets the value for the given option key
380
- *
381
- * @param string $insKey
382
- * @param mixed $inmValue
383
- * @return boolean
384
- */
385
- public function setOpt( $insKey, $inmValue ) {
386
 
387
- if ( !$this->getIsOptionKey( $insKey ) ) {
388
- return false;
 
 
 
 
 
 
389
  }
390
 
391
- if ( !isset( $this->m_aOptionsValues ) ) {
392
- $this->loadStoredOptionsValues();
 
 
 
393
  }
394
 
395
- if ( $this->getOpt( $insKey ) === $inmValue ) {
396
- return true;
 
 
 
397
  }
398
- $this->m_aOptionsValues[ $insKey ] = $inmValue;
399
- $this->fNeedSave = true;
400
- return true;
401
- }
402
 
403
- /**
404
- * @param string $sOptionKey
405
- * @return mixed
406
- */
407
- public function getOpt( $sOptionKey ) {
408
- if ( !isset( $this->m_aOptionsValues ) ) {
409
- $this->loadStoredOptionsValues();
410
  }
411
- return ( isset( $this->m_aOptionsValues[ $sOptionKey ] )? $this->m_aOptionsValues[ $sOptionKey ] : false );
412
- }
413
-
414
- /**
415
- * Retrieves the full array of options->values
416
- *
417
- * @return array
418
- */
419
- public function getOptions() {
420
- $this->buildOptions();
421
- return $this->aOptions;
422
- }
423
 
424
- /**
425
- * Loads the options and their stored values from the WordPress Options store.
426
- *
427
- * @return array
428
- */
429
- public function getPluginOptionsValues() {
430
- $this->generateOptionsValues();
431
- return $this->m_aOptionsValues;
432
- }
433
-
434
- /**
435
- * Saves the options to the WordPress Options store.
436
- *
437
- * It will also update the stored plugin options version.
438
- */
439
- public function savePluginOptions() {
440
-
441
- $this->doPrePluginOptionsSave();
442
- $this->cleanOptions();
443
- $this->updateOptionsVersion();
444
- if ( !$this->fNeedSave ) {
445
- return true;
446
  }
447
 
448
- $oWpFunc = $this->loadWpFunctions();
449
- $oWpFunc->updateOption( $this->sOptionsStoreKey, $this->m_aOptionsValues );
450
- $this->fNeedSave = false;
451
- return true;
452
- }
453
-
454
- /**
455
- *
456
- */
457
- protected function cleanOptions() {
458
- foreach( $this->m_aOptionsValues as $sKey => $mValue ) {
459
- if ( !$this->getIsOptionKey( $sKey ) ) {
460
- unset( $this->m_aOptionsValues[$sKey] );
461
  }
 
462
  }
463
- }
464
-
465
- public function collateAllFormInputsForAllOptions() {
466
-
467
- if ( !isset( $this->aOptions ) ) {
468
- $this->buildOptions();
469
- }
470
-
471
- $aToJoin = array();
472
- foreach ( $this->aOptions as $aOptionsSection ) {
473
 
474
- if ( empty( $aOptionsSection ) ) {
475
- continue;
 
 
 
 
 
 
476
  }
477
- foreach ( $aOptionsSection['section_options'] as $aOption ) {
478
- list($sKey, $fill1, $fill2, $sType) = $aOption;
479
- $aToJoin[] = $sType.':'.$sKey;
480
- }
481
- }
482
- return implode( self::CollateSeparator, $aToJoin );
483
- }
484
 
485
- /**
486
- * @return array
487
- */
488
- protected function generateOptionsValues() {
489
- if ( !isset( $this->m_aOptionsValues ) ) {
490
- $this->loadStoredOptionsValues();
491
- }
492
- if ( empty( $this->m_aOptionsValues ) ) {
493
- $this->buildOptions(); // set the defaults
494
  }
495
- }
496
-
497
- /**
498
- * @param $aAggregatedOptions
499
- * @return array
500
- */
501
- public function aggregateOptionsValues( $aAggregatedOptions ) {
502
- return array_merge( $aAggregatedOptions, $this->loadStoredOptionsValues() );
503
- }
504
 
505
- /**
506
- * Loads the options and their stored values from the WordPress Options store.
507
- */
508
- protected function loadStoredOptionsValues() {
509
- if ( empty( $this->m_aOptionsValues ) ) {
510
- $oWpFunc = $this->loadWpFunctions();
511
- $this->m_aOptionsValues = $oWpFunc->getOption( $this->sOptionsStoreKey, array() );
512
- if ( empty( $this->m_aOptionsValues ) ) {
513
- $this->fNeedSave = true;
514
  }
515
- }
516
- return $this->m_aOptionsValues;
517
- }
518
 
519
- /**
520
- */
521
- protected function defineOptions() {
522
- $this->aOptions = $this->getOptionsDefinitions();
 
523
 
524
- // All features store the current plugin version.
525
- $this->aNonUiOptions = array( self::PluginVersionKey );
526
- $aNonUiOptions = $this->getNonUiOptions();
527
- if ( !empty( $aNonUiOptions ) || is_array( $aNonUiOptions ) ) {
528
- $this->aNonUiOptions = array_merge( $this->aNonUiOptions, $aNonUiOptions );
529
  }
530
- }
531
-
532
- /**
533
- * @return array
534
- */
535
- protected function getOptionsDefinitions() {
536
- $aMisc = array(
537
- 'section_title' => 'Miscellaneous Plugin Options',
538
- 'section_options' => array(
539
- array(
540
- 'delete_on_deactivate',
541
- '',
542
- 'N',
543
- 'checkbox',
544
- 'Delete Plugin Settings',
545
- 'Delete All Plugin Settings Upon Plugin Deactivation',
546
- 'Careful: Removes all plugin options when you deactivite the plugin.'
547
- ),
548
- ),
549
- );
550
- $aOptionsDefinitions = array(
551
- $aMisc
552
- );
553
- return $aOptionsDefinitions;
554
- }
555
-
556
- /**
557
- * @return array
558
- */
559
- protected function getNonUiOptions() {
560
- return array();
561
- }
562
-
563
- /**
564
- * Will initiate the plugin options structure for use by the UI builder.
565
- *
566
- * It will also fill in $this->m_aOptionsValues with defaults where appropriate.
567
- *
568
- * It doesn't set any values, just populates the array created in buildOptions()
569
- * with values stored.
570
- *
571
- * It has to handle the conversion of stored values to data to be displayed to the user.
572
- */
573
- public function buildOptions() {
574
-
575
- $this->defineOptions();
576
- $this->loadStoredOptionsValues();
577
 
578
- $this->aOptionsKeys = array();
579
- foreach ( $this->aOptions as &$aOptionsSection ) {
580
-
581
- if ( empty( $aOptionsSection ) || !isset( $aOptionsSection['section_options'] ) ) {
582
- continue;
 
583
  }
584
 
585
- foreach ( $aOptionsSection['section_options'] as &$aOptionParams ) {
586
-
587
- list( $sOptionKey, $sOptionValue, $sOptionDefault, $sOptionType ) = $aOptionParams;
588
-
589
- $this->aOptionsKeys[] = $sOptionKey;
 
 
 
 
590
 
591
- if ( $this->getOpt( $sOptionKey ) === false ) {
592
- $this->setOpt( $sOptionKey, $sOptionDefault );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
593
  }
594
- $mCurrentOptionVal = $this->getOpt( $sOptionKey );
595
 
596
- if ( $sOptionType == 'password' && !empty( $mCurrentOptionVal ) ) {
597
- $mCurrentOptionVal = '';
598
- }
599
- else if ( $sOptionType == 'ip_addresses' ) {
600
 
601
- if ( empty( $mCurrentOptionVal ) ) {
602
- $mCurrentOptionVal = '';
603
- }
604
- else {
605
- $mCurrentOptionVal = implode( "\n", $this->convertIpListForDisplay( $mCurrentOptionVal ) );
 
606
  }
607
- }
608
- else if ( $sOptionType == 'yubikey_unique_keys' ) {
609
 
610
- if ( empty( $mCurrentOptionVal ) ) {
611
  $mCurrentOptionVal = '';
612
  }
613
- else {
614
- $aDisplay = array();
615
- foreach( $mCurrentOptionVal as $aParts ) {
616
- $aDisplay[] = key($aParts) .', '. reset($aParts);
 
 
 
617
  }
618
- $mCurrentOptionVal = implode( "\n", $aDisplay );
619
  }
620
- }
621
- else if ( $sOptionType == 'comma_separated_lists' ) {
622
 
623
- if ( empty( $mCurrentOptionVal ) ) {
624
- $mCurrentOptionVal = '';
 
 
 
 
 
 
 
 
625
  }
626
- else {
627
- $aNewValues = array();
628
- foreach( $mCurrentOptionVal as $sPage => $aParams ) {
629
- $aNewValues[] = $sPage.', '. implode( ", ", $aParams );
 
 
 
 
 
 
 
630
  }
631
- $mCurrentOptionVal = implode( "\n", $aNewValues );
632
  }
633
- }
634
- $aOptionParams[1] = $mCurrentOptionVal;
635
- }
636
- }
637
 
638
- // Cater for Non-UI options that don't necessarily go through the UI
639
- if ( isset( $this->aNonUiOptions ) && is_array( $this->aNonUiOptions ) ) {
640
- foreach( $this->aNonUiOptions as $sOption ) {
641
- $this->aOptionsKeys[] = $sOption;
642
- if ( !$this->getOpt( $sOption ) ) {
643
- $this->setOpt( $sOption, '' );
644
  }
645
- }
646
- }
647
- }
648
-
649
- /**
650
- * This is the point where you would want to do any options verification
651
- */
652
- protected function doPrePluginOptionsSave() { }
653
 
654
- /**
655
- */
656
- protected function updateOptionsVersion() {
657
- $this->setOpt( self::PluginVersionKey, $this->oPluginVo->getVersion() );
658
- }
659
 
660
- /**
661
- * Deletes all the options including direct save.
662
- */
663
- public function deletePluginOptions() {
664
- if ( apply_filters( $this->doPluginPrefix( 'has_permission_to_submit' ), true ) ) {
665
- $oWpFunc = $this->loadWpFunctions();
666
- $oWpFunc->deleteOption( $this->sOptionsStoreKey );
667
 
668
- $this->getProcessor()->deleteAndCleanUp(); // gets rid of the databases used by the processors.
 
 
 
 
 
669
 
670
- //prevents resaving
671
- remove_action( $this->doPluginPrefix( 'plugin_shutdown' ), array( $this, 'action_doFeatureShutdown' ) );
 
 
 
672
  }
673
- }
674
 
675
- protected function convertIpListForDisplay( $inaIpList = array() ) {
 
 
 
676
 
677
- $aDisplay = array();
678
- if ( empty( $inaIpList ) || empty( $inaIpList['ips'] ) ) {
679
- return $aDisplay;
 
680
  }
681
- foreach( $inaIpList['ips'] as $sAddress ) {
682
- // offset=1 in the case that it's a range and the first number is negative on 32-bit systems
683
- $mPos = strpos( $sAddress, '-', 1 );
684
 
685
- if ( $mPos === false ) { //plain IP address
686
- $sDisplayText = long2ip( $sAddress );
687
- }
688
- else {
689
- //we remove the first character in case this is '-'
690
- $aParts = array( substr( $sAddress, 0, 1 ), substr( $sAddress, 1 ) );
691
- list( $nStart, $nEnd ) = explode( '-', $aParts[1], 2 );
692
- $sDisplayText = long2ip( $aParts[0].$nStart ) .'-'. long2ip( $nEnd );
693
  }
694
- $sLabel = $inaIpList['meta'][ md5($sAddress) ];
695
- $sLabel = trim( $sLabel, '()' );
696
- $aDisplay[] = $sDisplayText . ' ('.$sLabel.')';
697
- }
698
- return $aDisplay;
699
- }
700
-
701
- /**
702
- *
703
- */
704
- public function handleFormSubmit() {
705
- if ( !apply_filters( $this->doPluginPrefix( 'has_permission_to_submit' ), true ) ) {
706
- // TODO: manage how we react to prohibited submissions
707
- return false;
708
  }
709
 
710
- // Now verify this is really a valid submission.
711
- check_admin_referer( $this->oPluginVo->getFullPluginPrefix() );
712
-
713
- $this->loadDataProcessor();
714
- $sAllOptions = ICWP_WPSF_DataProcessor::FetchPost( $this->doPluginPrefix( 'all_options_input', '_' ) );
715
-
716
- if ( empty( $sAllOptions ) ) {
717
- return true;
718
- }
719
 
720
- $this->updatePluginOptionsFromSubmit( $sAllOptions ); //it also saves
721
- return true;
722
- }
 
 
 
 
723
 
724
- /**
725
- * @param string $sAllOptionsInput - comma separated list of all the input keys to be processed from the $_POST
726
- * @return void|boolean
727
- */
728
- public function updatePluginOptionsFromSubmit( $sAllOptionsInput ) {
729
- if ( empty( $sAllOptionsInput ) ) {
730
- return;
 
 
 
 
 
 
 
731
  }
732
- $this->loadDataProcessor();
733
- $this->loadStoredOptionsValues();
734
 
735
- $aAllInputOptions = explode( self::CollateSeparator, $sAllOptionsInput );
736
- foreach ( $aAllInputOptions as $sInputKey ) {
737
- $aInput = explode( ':', $sInputKey );
738
- list( $sOptionType, $sOptionKey ) = $aInput;
739
 
740
- if ( !$this->getIsOptionKey( $sOptionKey ) ) {
741
- continue;
742
- }
743
 
744
- $sOptionValue = ICWP_WPSF_DataProcessor::FetchPost( $this->prefixOptionKey( $sOptionKey ) );
745
- if ( is_null($sOptionValue) ) {
746
 
747
- if ( $sOptionType == 'text' || $sOptionType == 'email' ) { //if it was a text box, and it's null, don't update anything
748
  continue;
749
  }
750
- else if ( $sOptionType == 'checkbox' ) { //if it was a checkbox, and it's null, it means 'N'
751
- $sOptionValue = 'N';
752
- }
753
- else if ( $sOptionType == 'integer' ) { //if it was a integer, and it's null, it means '0'
754
- $sOptionValue = 0;
755
  }
756
  }
757
- else { //handle any pre-processing we need to.
 
758
 
759
- if ( $sOptionType == 'integer' ) {
760
- $sOptionValue = intval( $sOptionValue );
761
- }
762
- else if ( $sOptionType == 'password' && $this->hasEncryptOption() ) { //md5 any password fields
763
- $sTempValue = trim( $sOptionValue );
764
- if ( empty( $sTempValue ) ) {
765
- continue;
766
- }
767
- $sOptionValue = md5( $sTempValue );
768
- }
769
- else if ( $sOptionType == 'ip_addresses' ) { //ip addresses are textareas, where each is separated by newline
770
- $sOptionValue = ICWP_WPSF_DataProcessor::ExtractIpAddresses( $sOptionValue );
771
- }
772
- else if ( $sOptionType == 'yubikey_unique_keys' ) { //ip addresses are textareas, where each is separated by newline and are 12 chars long
773
- $sOptionValue = ICWP_WPSF_DataProcessor::CleanYubikeyUniqueKeys( $sOptionValue );
774
- }
775
- else if ( $sOptionType == 'email' && function_exists( 'is_email' ) && !is_email( $sOptionValue ) ) {
776
- $sOptionValue = '';
777
- }
778
- else if ( $sOptionType == 'comma_separated_lists' ) {
779
- $sOptionValue = ICWP_WPSF_DataProcessor::ExtractCommaSeparatedList( $sOptionValue );
780
- }
781
  }
782
- $this->setOpt( $sOptionKey, $sOptionValue );
783
- }
784
- return $this->savePluginOptions();
785
- }
786
 
787
- /**
788
- * Should be over-ridden by each new class to handle upgrades.
789
- *
790
- * Called upon construction and after plugin options are initialized.
791
- */
792
- protected function updateHandler() {
793
- if ( version_compare( $this->getVersion(), '3.0.0', '<' ) ) {
794
- $oWpFunctions = $this->loadWpFunctions();
795
- $sKey = $this->doPluginPrefix( $this->getFeatureSlug().'_processor', '_' );
796
- $oWpFunctions->deleteOption( $sKey );
797
  }
798
- }
799
-
800
- /**
801
- * @return boolean
802
- */
803
- public function hasEncryptOption() {
804
- return function_exists( 'md5' );
805
- // return extension_loaded( 'mcrypt' );
806
- }
807
 
808
- protected function getVisitorIpAddress( $infAsLong = true ) {
809
- $this->loadDataProcessor();
810
- return ICWP_WPSF_DataProcessor::GetVisitorIpAddress( $infAsLong );
811
- }
 
812
 
813
- /**
814
- * Prefixes an option key only if it's needed
815
- *
816
- * @param $sKey
817
- * @return string
818
- */
819
- protected function prefixOptionKey( $sKey ) {
820
- return $this->doPluginPrefix( $sKey, '_' );
821
- }
822
 
823
- /**
824
- * Will prefix and return any string with the unique plugin prefix.
825
- *
826
- * @param string $sSuffix
827
- * @param string $sGlue
828
- * @return string
829
- */
830
- public function doPluginPrefix( $sSuffix = '', $sGlue = '-' ) {
831
- $sPrefix = $this->oPluginVo->getFullPluginPrefix( $sGlue );
832
 
833
- if ( $sSuffix == $sPrefix || strpos( $sSuffix, $sPrefix.$sGlue ) === 0 ) { //it already has the prefix
834
- return $sSuffix;
 
 
835
  }
836
 
837
- return sprintf( '%s%s%s', $sPrefix, empty($sSuffix)? '' : $sGlue, empty($sSuffix)? '' : $sSuffix );
838
- }
839
 
840
- /**
841
- * @param string
842
- * @return string
843
- */
844
- public function getOptionStoragePrefix() {
845
- return $this->oPluginVo->getFullPluginPrefix( '_' ).'_';
846
- }
 
 
847
 
848
- /**
849
- * @param string $insExistingListKey
850
- * @param string $insFilterName
851
- * @return array|false
852
- */
853
- protected function processIpFilter( $insExistingListKey, $insFilterName ) {
854
- $aFilterIps = apply_filters( $insFilterName, array() );
855
- if ( empty( $aFilterIps ) ) {
856
- return false;
857
- }
858
 
859
- $aNewIps = array();
860
- foreach( $aFilterIps as $mKey => $sValue ) {
861
- if ( is_string( $mKey ) ) { //it's the IP
862
- $sIP = $mKey;
863
- $sLabel = $sValue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
864
  }
865
- else { //it's not an associative array, so the value is the IP
866
- $sIP = $sValue;
867
- $sLabel = '';
 
 
 
 
 
 
 
 
 
 
868
  }
869
- $aNewIps[ $sIP ] = $sLabel;
870
  }
871
 
872
- // now add and store the new IPs
873
- $aExistingIpList = $this->getOpt( $insExistingListKey );
874
- if ( !is_array( $aExistingIpList ) ) {
875
- $aExistingIpList = array();
876
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
877
 
878
- $this->loadDataProcessor();
879
- $nNewAddedCount = 0;
880
- $aNewList = ICWP_WPSF_DataProcessor::Add_New_Raw_Ips( $aExistingIpList, $aNewIps, $nNewAddedCount );
881
- if ( $nNewAddedCount > 0 ) {
882
- $this->setOpt( $insExistingListKey, $aNewList );
883
- }
884
- }
 
 
 
 
 
885
 
886
- /**
887
- */
888
- public function displayFeatureConfigPage( ) {
 
 
889
 
890
- if ( !apply_filters( $this->doPluginPrefix( 'has_permission_to_view' ), true ) ) {
891
- $this->displayViewAccessRestrictedPage();
892
- return;
 
 
 
893
  }
894
 
895
- // $aPluginSummaryData = apply_filters( $this->doPluginPrefix( 'get_feature_summary_data' ), array() );
896
- $aData = array(
897
- 'aSummaryData' => isset( $aPluginSummaryData ) ? $aPluginSummaryData : array()
898
- );
899
- $aData = array_merge( $this->getBaseDisplayData(), $aData );
900
- $this->display( $aData );
901
- }
902
-
903
- public function getIsCurrentPageConfig() {
904
- $oWpFunctions = $this->loadWpFunctions();
905
- return $oWpFunctions->getCurrentWpAdminPage() == $this->doPluginPrefix( $this->sFeatureSlug );
906
- }
907
 
908
- /**
909
- */
910
- public function displayViewAccessRestrictedPage( ) {
911
- $aData = array(
912
- 'requested_page' => $this->doPluginPrefix( $this->sFeatureSlug )
913
- );
914
- $aData = array_merge( $this->getBaseDisplayData(), $aData );
915
- $this->display( $aData, 'access_restricted_index' );
916
- }
917
 
918
- protected function getBaseDisplayData() {
919
- return array(
920
- 'var_prefix' => $this->oPluginVo->getOptionStoragePrefix(),
921
- 'sPluginName' => $this->oPluginVo->getHumanName(),
922
- 'sFeatureName' => $this->getMainFeatureName(),
923
- 'fShowAds' => $this->getIsShowMarketing(),
924
- 'nonce_field' => $this->oPluginVo->getFullPluginPrefix(),
925
- 'form_action' => 'admin.php?page='.$this->doPluginPrefix( $this->sFeatureSlug ),
926
-
927
- 'aAllOptions' => $this->getOptions(),
928
- 'all_options_input' => $this->collateAllFormInputsForAllOptions()
929
- );
930
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931
 
932
- /**
933
- * @return boolean
934
- */
935
- protected function getIsShowMarketing() {
936
- return apply_filters( $this->doPluginPrefix( 'show_marketing' ), true );
937
- }
938
 
939
- /**
940
- * @param array $inaData
941
- * @param string $sView
942
- * @return bool
943
- */
944
- protected function display( $inaData = array(), $sView = '' ) {
945
 
946
- if ( empty( $sView ) ) {
947
- $oWpFs = $this->loadFileSystemProcessor();
948
- $sCustomViewSource = $this->oPluginVo->getViewDir().$this->doPluginPrefix( 'config_'.$this->sFeatureSlug.'_index' ).'.php';
949
- $sNormalViewSource = $this->oPluginVo->getViewDir().$this->doPluginPrefix( 'config_index' ).'.php';
950
- $sFile = $oWpFs->exists( $sCustomViewSource ) ? $sCustomViewSource : $sNormalViewSource;
951
- }
952
- else {
953
- $sFile = $this->oPluginVo->getViewDir().$this->doPluginPrefix( $sView ).'.php';
954
- }
955
 
956
- if ( !is_file( $sFile ) ) {
957
- echo "View not found: ".$sFile;
958
- return false;
959
  }
960
 
961
- if ( count( $inaData ) > 0 ) {
962
- extract( $inaData, EXTR_PREFIX_ALL, $this->oPluginVo->getParentSlug() ); //slug being 'icwp'
 
 
 
 
963
  }
964
 
965
- ob_start();
966
- include( $sFile );
967
- $sContents = ob_get_contents();
968
- ob_end_clean();
969
-
970
- echo $sContents;
971
- return true;
972
- }
973
-
974
- protected function loadDataProcessor() {
975
- if ( !class_exists('ICWP_WPSF_DataProcessor') ) {
976
- require_once( dirname(__FILE__).'/icwp-data-processor.php' );
977
  }
978
- }
979
 
980
- /**
981
- * @return ICWP_WpFunctions_WPSF
982
- */
983
- protected function loadWpFunctions() {
984
- return ICWP_WpFunctions_WPSF::GetInstance();
985
- }
986
-
987
- /**
988
- * @return ICWP_WpFilesystem_WPSF
989
- */
990
- protected function loadFileSystemProcessor() {
991
- if ( !class_exists('ICWP_WpFilesystem_WPSF') ) {
992
- require_once( dirname(__FILE__) . '/icwp-wpfilesystem.php' );
993
  }
994
- return ICWP_WpFilesystem_WPSF::GetInstance();
995
  }
996
 
997
- }
998
-
999
  endif;
1000
 
1001
- class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_FeatureHandler_Base_V2 { }
3
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
 
 
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( 'icwp-options-vo.php' );
19
  if ( !class_exists('ICWP_WPSF_FeatureHandler_Base_V2') ):
20
 
21
+ abstract class ICWP_WPSF_FeatureHandler_Base_V2 extends ICWP_WPSF_Foundation {
22
+
23
+ /**
24
+ * @var ICWP_WPSF_Plugin_Controller
25
+ */
26
+ protected $oPluginController;
27
+
28
+ /**
29
+ * @var ICWP_WPSF_OptionsVO
30
+ */
31
+ protected $oOptions;
32
+
33
+ /**
34
+ * @var string
35
+ */
36
+ const CollateSeparator = '--SEP--';
37
+ /**
38
+ * @var string
39
+ */
40
+ const PluginVersionKey = 'current_plugin_version';
41
+
42
+ /**
43
+ * @var boolean
44
+ */
45
+ protected $fPluginDeleting = false;
46
+
47
+ /**
48
+ * @var string
49
+ */
50
+ protected $sOptionsStoreKey;
51
+
52
+ /**
53
+ * @var string
54
+ */
55
+ protected $sFeatureName;
56
+
57
+ /**
58
+ * @var string
59
+ */
60
+ protected $sFeatureSlug;
61
+
62
+ /**
63
+ * @var string
64
+ */
65
+ protected static $sPluginBaseFile;
66
+
67
+ /**
68
+ * @var ICWP_WPSF_FeatureHandler_Email
69
+ */
70
+ protected static $oEmailHandler;
71
+
72
+ /**
73
+ * @var ICWP_WPSF_FeatureHandler_Email
74
+ */
75
+ protected static $oLoggingHandler;
76
+
77
+ /**
78
+ * @var ICWP_WPSF_Processor_Base
79
+ */
80
+ protected $oFeatureProcessor;
81
+
82
+ /**
83
+ * @var boolean
84
+ */
85
+ protected $fOverrideState;
86
+
87
+ public function __construct( $oPluginController, $sOptionsStoreKey = null ) {
88
+ if ( empty( $oPluginController ) ) {
89
+ throw new Exception();
90
+ }
91
+ $this->oPluginController = $oPluginController;
92
+ $this->sOptionsStoreKey = $this->prefixOptionKey(
93
+ ( is_null( $sOptionsStoreKey ) ? $this->getFeatureSlug() : $sOptionsStoreKey )
94
+ .'_options'
95
+ );
96
+
97
+ // Handle any upgrades as necessary (only go near this if it's the admin area)
98
+ add_action( 'plugins_loaded', array( $this, 'onWpPluginsLoaded' ) );
99
+ add_action( 'init', array( $this, 'onWpInit' ), 1 );
100
+ add_action( $this->doPluginPrefix( 'form_submit' ), array( $this, 'handleFormSubmit' ) );
101
+ add_filter( $this->doPluginPrefix( 'filter_plugin_submenu_items' ), array( $this, 'filter_addPluginSubMenuItem' ) );
102
+ add_filter( $this->doPluginPrefix( 'get_feature_summary_data' ), array( $this, 'filter_getFeatureSummaryData' ) );
103
+ add_filter( $this->doPluginPrefix( 'flush_logs' ), array( $this, 'filter_flushFeatureLogs' ) );
104
+ add_action( $this->doPluginPrefix( 'plugin_shutdown' ), array( $this, 'action_doFeatureShutdown' ) );
105
+ add_action( $this->doPluginPrefix( 'delete_plugin' ), array( $this, 'deletePluginOptions' ) );
106
+ add_filter( $this->doPluginPrefix( 'aggregate_all_plugin_options' ), array( $this, 'aggregateOptionsValues' ) );
107
+ }
108
+
109
+ /**
110
+ * A action added to WordPress 'plugins_loaded' hook
111
+ */
112
+ public function onWpPluginsLoaded() {
113
+
114
+ if ( $this->getIsMainFeatureEnabled() ) {
115
+ $oProcessor = $this->getProcessor();
116
+ if ( is_object( $oProcessor ) && $oProcessor instanceof ICWP_WPSF_Processor_Base ) {
117
+ $oProcessor->run();
118
+ }
119
+ }
 
 
 
 
 
 
 
 
 
 
 
120
  }
 
 
 
 
 
121
 
122
+ /**
123
+ * A action added to WordPress 'init' hook
124
+ */
125
+ public function onWpInit() {
126
+ $this->updateHandler();
127
+ }
 
 
 
 
 
 
128
 
129
+ /**
130
+ * Override this and adapt per feature
131
+ * @return null
132
+ */
133
+ abstract protected function loadFeatureProcessor();
134
 
135
+ /**
136
+ * @return ICWP_WPSF_OptionsVO
137
+ */
138
+ public function getOptionsVo() {
139
+ if ( !isset( $this->oOptions ) ) {
140
+ $this->oOptions = new ICWP_WPSF_OptionsVO( $this->getFeatureSlug() );
141
+ $this->oOptions->setOptionsStorageKey( $this->getOptionsStorageKey() );
142
+ }
143
+ return $this->oOptions;
144
  }
145
 
146
+ /**
147
+ * @return bool
148
+ */
149
+ public function getIsUpgrading() {
150
+ return $this->getVersion() != $this->getController()->getVersion();
151
  }
152
 
153
+ /**
154
+ * Hooked to the plugin's main plugin_shutdown action
155
+ */
156
+ public function action_doFeatureShutdown() {
157
 
158
+ if ( ! $this->fPluginDeleting ) {
159
+ $this->savePluginOptions();
 
 
 
 
 
160
 
161
+ if ( $this->getController()->getIsLoggingEnabled() ) {
162
+ $aLogData = apply_filters( $this->doPluginPrefix( 'flush_logs' ), array() );
163
+ $oLoggingProcessor = $this->getLoggingProcessor();
164
+ $oLoggingProcessor->addDataToWrite( $aLogData );
165
+ $oLoggingProcessor->commitData();
166
+ }
167
+ }
 
 
 
 
 
 
168
  }
 
 
 
 
 
 
 
 
 
169
 
170
+ /**
171
+ * @return string
172
+ */
173
+ protected function getOptionsStorageKey() {
174
+ if ( !isset( $this->sOptionsStoreKey ) ) {
175
+ // not ideal as it doesn't take into account custom storage keys as when passed into the constructor
176
+ $this->sOptionsStoreKey = $this->prefixOptionKey( $this->getFeatureSlug().'_options' );
177
+ }
178
+ return $this->sOptionsStoreKey;
179
  }
 
 
 
 
 
 
 
 
 
180
 
181
+ /**
182
+ * @return ICWP_WPSF_Processor_Base
183
+ */
184
+ public function getProcessor() {
185
+ return $this->loadFeatureProcessor();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  }
 
 
187
 
188
+ /**
189
+ * @return ICWP_WPSF_FeatureHandler_Email
190
+ */
191
+ public function getEmailHandler() {
192
+ if ( is_null( self::$oEmailHandler ) ) {
193
+ self::$oEmailHandler = new ICWP_WPSF_FeatureHandler_Email( $this->getController() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  }
195
+ return self::$oEmailHandler;
196
  }
 
 
197
 
198
+ /**
199
+ * @return ICWP_WPSF_Processor_Email
200
+ */
201
+ public function getEmailProcessor() {
202
+ return $this->getEmailHandler()->getProcessor();
 
 
203
  }
 
 
 
 
 
 
 
 
204
 
205
+ /**
206
+ * @return ICWP_WPSF_FeatureHandler_Logging
207
+ */
208
+ public function getLoggingHandler() {
209
+ if ( is_null( self::$oLoggingHandler ) ) {
210
+ require_once( 'icwp-optionshandler-logging.php' );
211
+ self::$oLoggingHandler = new ICWP_WPSF_FeatureHandler_Logging( $this->getController() );
212
+ }
213
+ return self::$oLoggingHandler;
214
  }
215
 
216
+ /**
217
+ * @return ICWP_WPSF_Processor_Logging
218
+ */
219
+ public function getLoggingProcessor() {
220
+ return $this->getLoggingHandler()->getProcessor();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  }
222
 
223
+ /**
224
+ * @param $fEnable
225
+ */
226
+ public function setIsMainFeatureEnabled( $fEnable ) {
227
+ $this->setOpt( 'enable_'.$this->getFeatureSlug(), $fEnable ? 'Y' : 'N' );
 
228
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
 
230
+ /**
231
+ * @return mixed
232
+ */
233
+ public function getIsMainFeatureEnabled() {
234
+ $fOverride = $this->getIfOverride();
235
+ if ( $fOverride ) {
236
+ return !$fOverride;
237
+ }
238
+ return $this->getOptIs( 'enable_'.$this->getFeatureSlug(), 'Y' ) || $this->getOptIs( 'enable_'.$this->getFeatureSlug(), true, true ) ;
239
  }
 
 
240
 
241
+ /**
242
+ * Returns true if you're overriding OFF. We don't do override ON any more (as of 3.5.1)
243
+ */
244
+ public function getIfOverride() {
 
 
 
 
 
 
245
 
246
+ if ( !is_null( $this->fOverrideState ) ) {
247
+ return $this->fOverrideState;
248
+ }
 
 
 
 
 
249
 
250
+ $oWpFs = $this->loadFileSystemProcessor();
251
+ if ( $oWpFs->fileExistsInDir( 'forceOff', $this->getController()->getRootDir(), false ) ) {
252
+ $this->fOverrideState = true;
253
+ }
254
+ else {
255
+ $this->fOverrideState = false;
256
+ }
257
+ return $this->fOverrideState;
258
  }
259
 
260
+ /**
261
+ * @return string
262
+ */
263
+ protected function getMainFeatureName() {
264
+ return $this->sFeatureName;
265
  }
266
 
267
+ /**
268
+ * @return string
269
+ */
270
+ public function getPluginBaseFile() {
271
+ return $this->getController()->getPluginBaseFile();
272
  }
 
 
 
 
273
 
274
+ /**
275
+ * @return string
276
+ */
277
+ public function getFeatureSlug() {
278
+ return $this->sFeatureSlug;
 
 
279
  }
 
 
 
 
 
 
 
 
 
 
 
 
280
 
281
+ /**
282
+ * With trailing slash
283
+ * @param string $sSourceFile
284
+ * @return string
285
+ */
286
+ public function getResourcesDir( $sSourceFile = '' ) {
287
+ return $this->getController()->getRootDir().'resources'.ICWP_DS.ltrim( $sSourceFile, ICWP_DS );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  }
289
 
290
+ /**
291
+ * @param array $aLogs
292
+ * @return array
293
+ */
294
+ public function filter_flushFeatureLogs( $aLogs ) {
295
+ if ( $this->getIsMainFeatureEnabled() ) {
296
+ $aFeatureLogs = $this->getProcessor()->flushLogData();
297
+ if ( !empty( $aFeatureLogs ) ) {
298
+ $aLogs = array_merge( $aLogs, $aFeatureLogs );
299
+ }
 
 
 
300
  }
301
+ return $aLogs;
302
  }
 
 
 
 
 
 
 
 
 
 
303
 
304
+ /**
305
+ * @param array $aItems
306
+ * @return array
307
+ */
308
+ public function filter_addPluginSubMenuItem( $aItems ) {
309
+ $sName = $this->getMainFeatureName();
310
+ if ( !$this->getIfShowFeatureMenuItem() || empty( $sName ) ) {
311
+ return $aItems;
312
  }
 
 
 
 
 
 
 
313
 
314
+ $sMenuPageTitle = $this->getController()->getHumanName().' - '.$sName;
315
+ $aItems[ $sMenuPageTitle ] = array(
316
+ $sName,
317
+ $this->doPluginPrefix( $this->getFeatureSlug() ),
318
+ array( $this, 'displayFeatureConfigPage' )
319
+ );
320
+ return $aItems;
 
 
321
  }
 
 
 
 
 
 
 
 
 
322
 
323
+ /**
324
+ * @param array $aSummaryData
325
+ * @return array
326
+ */
327
+ public function filter_getFeatureSummaryData( $aSummaryData ) {
328
+ if ( !$this->getIfShowFeatureMenuItem() ) {
329
+ return $aSummaryData;
 
 
330
  }
 
 
 
331
 
332
+ $aSummaryData[] = array(
333
+ $this->getIsMainFeatureEnabled(),
334
+ $this->getMainFeatureName(),
335
+ $this->doPluginPrefix( $this->getFeatureSlug() )
336
+ );
337
 
338
+ return $aSummaryData;
 
 
 
 
339
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
 
341
+ /**
342
+ * @return bool
343
+ */
344
+ public function hasPluginManageRights() {
345
+ if ( !current_user_can( $this->getController()->getBasePermissions() ) ) {
346
+ return false;
347
  }
348
 
349
+ $oWpFunc = $this->loadWpFunctionsProcessor();
350
+ if ( is_admin() && !$oWpFunc->isMultisite() ) {
351
+ return true;
352
+ }
353
+ else if ( is_network_admin() && $oWpFunc->isMultisite() ) {
354
+ return true;
355
+ }
356
+ return false;
357
+ }
358
 
359
+ /**
360
+ * @return boolean
361
+ */
362
+ public function getIfShowFeatureMenuItem() {
363
+ return $this->getOptionsVo()->getFeatureProperty( 'show_feature_menu_item' );
364
+ }
365
+
366
+ /**
367
+ * @param string $sOptionKey
368
+ * @param mixed $mDefault
369
+ * @return mixed
370
+ */
371
+ public function getOpt( $sOptionKey, $mDefault = false ) {
372
+ return $this->getOptionsVo()->getOpt( $sOptionKey, $mDefault );
373
+ }
374
+
375
+ /**
376
+ * @param string $sOptionKey
377
+ * @param mixed $mValueToTest
378
+ * @param boolean $fStrict
379
+ * @return bool
380
+ */
381
+ public function getOptIs( $sOptionKey, $mValueToTest, $fStrict = false ) {
382
+ $mOptionValue = $this->getOptionsVo()->getOpt( $sOptionKey );
383
+ return $fStrict? $mOptionValue === $mValueToTest : $mOptionValue == $mValueToTest;
384
+ }
385
+
386
+ /**
387
+ * Retrieves the full array of options->values
388
+ *
389
+ * @return array
390
+ */
391
+ public function getOptions() {
392
+ return $this->buildOptions();
393
+ }
394
+
395
+ /**
396
+ * @return string
397
+ */
398
+ public function getVersion() {
399
+ $sVersion = $this->getOpt( self::PluginVersionKey );
400
+ return empty( $sVersion )? '0.0' : $sVersion;
401
+ }
402
+
403
+ /**
404
+ * Sets the value for the given option key
405
+ *
406
+ * @param string $sOptionKey
407
+ * @param mixed $mValue
408
+ * @return boolean
409
+ */
410
+ public function setOpt( $sOptionKey, $mValue ) {
411
+ return $this->getOptionsVo()->setOpt( $sOptionKey, $mValue );
412
+ }
413
+
414
+ /**
415
+ * Saves the options to the WordPress Options store.
416
+ *
417
+ * It will also update the stored plugin options version.
418
+ */
419
+ public function savePluginOptions() {
420
+ $this->doPrePluginOptionsSave();
421
+ $this->updateOptionsVersion();
422
+ $this->getOptionsVo()->doOptionsSave();
423
+ }
424
+
425
+ /**
426
+ * @param $aAggregatedOptions
427
+ * @return array
428
+ */
429
+ public function aggregateOptionsValues( $aAggregatedOptions ) {
430
+ return array_merge( $aAggregatedOptions, $this->getOptionsVo()->getAllOptionsValues() );
431
+ }
432
+
433
+ /**
434
+ * Will initiate the plugin options structure for use by the UI builder.
435
+ *
436
+ * It doesn't set any values, just populates the array created in buildOptions()
437
+ * with values stored.
438
+ *
439
+ * It has to handle the conversion of stored values to data to be displayed to the user.
440
+ */
441
+ public function buildOptions() {
442
+
443
+ $aOptions = $this->getOptionsVo()->getLegacyOptionsConfigData();
444
+ foreach ( $aOptions as $nSectionKey => $aOptionsSection ) {
445
+
446
+ if ( empty( $aOptionsSection ) || !isset( $aOptionsSection['section_options'] ) ) {
447
+ continue;
448
  }
 
449
 
450
+ foreach ( $aOptionsSection['section_options'] as $nKey => $aOptionParams ) {
 
 
 
451
 
452
+ $sOptionKey = $aOptionParams['key'];
453
+ $sOptionDefault = $aOptionParams['default'];
454
+ $sOptionType = $aOptionParams['type'];
455
+
456
+ if ( $this->getOpt( $sOptionKey ) === false ) {
457
+ $this->setOpt( $sOptionKey, $sOptionDefault );
458
  }
459
+ $mCurrentOptionVal = $this->getOpt( $sOptionKey );
 
460
 
461
+ if ( $sOptionType == 'password' && !empty( $mCurrentOptionVal ) ) {
462
  $mCurrentOptionVal = '';
463
  }
464
+ else if ( $sOptionType == 'ip_addresses' ) {
465
+
466
+ if ( empty( $mCurrentOptionVal ) ) {
467
+ $mCurrentOptionVal = '';
468
+ }
469
+ else {
470
+ $mCurrentOptionVal = implode( "\n", $this->convertIpListForDisplay( $mCurrentOptionVal ) );
471
  }
 
472
  }
473
+ else if ( $sOptionType == 'yubikey_unique_keys' ) {
 
474
 
475
+ if ( empty( $mCurrentOptionVal ) ) {
476
+ $mCurrentOptionVal = '';
477
+ }
478
+ else {
479
+ $aDisplay = array();
480
+ foreach( $mCurrentOptionVal as $aParts ) {
481
+ $aDisplay[] = key($aParts) .', '. reset($aParts);
482
+ }
483
+ $mCurrentOptionVal = implode( "\n", $aDisplay );
484
+ }
485
  }
486
+ else if ( $sOptionType == 'comma_separated_lists' ) {
487
+
488
+ if ( empty( $mCurrentOptionVal ) ) {
489
+ $mCurrentOptionVal = '';
490
+ }
491
+ else {
492
+ $aNewValues = array();
493
+ foreach( $mCurrentOptionVal as $sPage => $aParams ) {
494
+ $aNewValues[] = $sPage.', '. implode( ", ", $aParams );
495
+ }
496
+ $mCurrentOptionVal = implode( "\n", $aNewValues );
497
  }
 
498
  }
499
+ $aOptionParams['value'] = $mCurrentOptionVal;
 
 
 
500
 
501
+ // Build strings
502
+ $aParamsWithStrings = $this->loadStrings_Options( $aOptionParams );
503
+ $aOptionsSection['section_options'][$nKey] = $aParamsWithStrings;
 
 
 
504
  }
 
 
 
 
 
 
 
 
505
 
506
+ $aOptions[$nSectionKey] = $this->loadStrings_SectionTitles( $aOptionsSection );
507
+ }
 
 
 
508
 
509
+ return $aOptions;
510
+ }
 
 
 
 
 
511
 
512
+ /**
513
+ * @param $aOptionsParams
514
+ */
515
+ protected function loadStrings_Options( $aOptionsParams ) {
516
+ return $aOptionsParams;
517
+ }
518
 
519
+ /**
520
+ * @param $aOptionsParams
521
+ */
522
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
523
+ return $aOptionsParams;
524
  }
 
525
 
526
+ /**
527
+ * This is the point where you would want to do any options verification
528
+ */
529
+ protected function doPrePluginOptionsSave() { }
530
 
531
+ /**
532
+ */
533
+ protected function updateOptionsVersion() {
534
+ $this->setOpt( self::PluginVersionKey, $this->getController()->getVersion() );
535
  }
 
 
 
536
 
537
+ /**
538
+ * Deletes all the options including direct save.
539
+ */
540
+ public function deletePluginOptions() {
541
+ if ( apply_filters( $this->doPluginPrefix( 'has_permission_to_submit' ), true ) ) {
542
+ $this->getOptionsVo()->doOptionsDelete();
543
+ $this->fPluginDeleting = true;
 
544
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
545
  }
546
 
547
+ protected function convertIpListForDisplay( $inaIpList = array() ) {
 
 
 
 
 
 
 
 
548
 
549
+ $aDisplay = array();
550
+ if ( empty( $inaIpList ) || empty( $inaIpList['ips'] ) ) {
551
+ return $aDisplay;
552
+ }
553
+ foreach( $inaIpList['ips'] as $sAddress ) {
554
+ // offset=1 in the case that it's a range and the first number is negative on 32-bit systems
555
+ $mPos = strpos( $sAddress, '-', 1 );
556
 
557
+ if ( $mPos === false ) { //plain IP address
558
+ $sDisplayText = long2ip( $sAddress );
559
+ }
560
+ else {
561
+ //we remove the first character in case this is '-'
562
+ $aParts = array( substr( $sAddress, 0, 1 ), substr( $sAddress, 1 ) );
563
+ list( $nStart, $nEnd ) = explode( '-', $aParts[1], 2 );
564
+ $sDisplayText = long2ip( $aParts[0].$nStart ) .'-'. long2ip( $nEnd );
565
+ }
566
+ $sLabel = $inaIpList['meta'][ md5($sAddress) ];
567
+ $sLabel = trim( $sLabel, '()' );
568
+ $aDisplay[] = $sDisplayText . ' ('.$sLabel.')';
569
+ }
570
+ return $aDisplay;
571
  }
 
 
572
 
573
+ /**
574
+ * @return string
575
+ */
576
+ protected function collateAllFormInputsForAllOptions() {
577
 
578
+ $aOptions = $this->getOptions();
 
 
579
 
580
+ $aToJoin = array();
581
+ foreach ( $aOptions as $aOptionsSection ) {
582
 
583
+ if ( empty( $aOptionsSection ) ) {
584
  continue;
585
  }
586
+ foreach ( $aOptionsSection['section_options'] as $aOption ) {
587
+ $aToJoin[] = $aOption['type'].':'.$aOption['key'];
 
 
 
588
  }
589
  }
590
+ return implode( self::CollateSeparator, $aToJoin );
591
+ }
592
 
593
+ /**
594
+ */
595
+ public function handleFormSubmit() {
596
+ $fVerified = $this->verifyFormSubmit();
597
+
598
+ if ( !$fVerified ) {
599
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  }
 
 
 
 
601
 
602
+ $this->doSaveStandardOptions();
603
+ $this->doExtraSubmitProcessing();
604
+ return true;
 
 
 
 
 
 
 
605
  }
 
 
 
 
 
 
 
 
 
606
 
607
+ protected function verifyFormSubmit() {
608
+ if ( !apply_filters( $this->doPluginPrefix( 'has_permission_to_submit' ), true ) ) {
609
+ // TODO: manage how we react to prohibited submissions
610
+ return false;
611
+ }
612
 
613
+ // Now verify this is really a valid submission.
614
+ return check_admin_referer( $this->getController()->getPluginPrefix() );
615
+ }
 
 
 
 
 
 
616
 
617
+ /**
618
+ * @return bool
619
+ */
620
+ protected function doSaveStandardOptions() {
621
+ $oDp = $this->loadDataProcessor();
622
+ $sAllOptions = $oDp->FetchPost( $this->prefixOptionKey( 'all_options_input' ) );
 
 
 
623
 
624
+ if ( empty( $sAllOptions ) ) {
625
+ return true;
626
+ }
627
+ $this->updatePluginOptionsFromSubmit( $sAllOptions ); //it also saves
628
  }
629
 
630
+ protected function doExtraSubmitProcessing() { }
 
631
 
632
+ /**
633
+ * @param string $sAllOptionsInput - comma separated list of all the input keys to be processed from the $_POST
634
+ * @return void|boolean
635
+ */
636
+ public function updatePluginOptionsFromSubmit( $sAllOptionsInput ) {
637
+ if ( empty( $sAllOptionsInput ) ) {
638
+ return;
639
+ }
640
+ $oDp = $this->loadDataProcessor();
641
 
642
+ $aAllInputOptions = explode( self::CollateSeparator, $sAllOptionsInput );
643
+ foreach ( $aAllInputOptions as $sInputKey ) {
644
+ $aInput = explode( ':', $sInputKey );
645
+ list( $sOptionType, $sOptionKey ) = $aInput;
 
 
 
 
 
 
646
 
647
+ $sOptionValue = $oDp->FetchPost( $this->prefixOptionKey( $sOptionKey ) );
648
+ if ( is_null( $sOptionValue ) ) {
649
+
650
+ if ( $sOptionType == 'text' || $sOptionType == 'email' ) { //if it was a text box, and it's null, don't update anything
651
+ continue;
652
+ }
653
+ else if ( $sOptionType == 'checkbox' ) { //if it was a checkbox, and it's null, it means 'N'
654
+ $sOptionValue = 'N';
655
+ }
656
+ else if ( $sOptionType == 'integer' ) { //if it was a integer, and it's null, it means '0'
657
+ $sOptionValue = 0;
658
+ }
659
+ }
660
+ else { //handle any pre-processing we need to.
661
+
662
+ if ( $sOptionType == 'text' || $sOptionType == 'email' ) {
663
+ $sOptionValue = trim( $sOptionValue );
664
+ }
665
+ if ( $sOptionType == 'integer' ) {
666
+ $sOptionValue = intval( $sOptionValue );
667
+ }
668
+ else if ( $sOptionType == 'password' && $this->hasEncryptOption() ) { //md5 any password fields
669
+ $sTempValue = trim( $sOptionValue );
670
+ if ( empty( $sTempValue ) ) {
671
+ continue;
672
+ }
673
+ $sOptionValue = md5( $sTempValue );
674
+ }
675
+ else if ( $sOptionType == 'ip_addresses' ) { //ip addresses are textareas, where each is separated by newline
676
+ $sOptionValue = $oDp->ExtractIpAddresses( $sOptionValue );
677
+ }
678
+ else if ( $sOptionType == 'yubikey_unique_keys' ) { //ip addresses are textareas, where each is separated by newline and are 12 chars long
679
+ $sOptionValue = $oDp->CleanYubikeyUniqueKeys( $sOptionValue );
680
+ }
681
+ else if ( $sOptionType == 'email' && function_exists( 'is_email' ) && !is_email( $sOptionValue ) ) {
682
+ $sOptionValue = '';
683
+ }
684
+ else if ( $sOptionType == 'comma_separated_lists' ) {
685
+ $sOptionValue = $oDp->ExtractCommaSeparatedList( $sOptionValue );
686
+ }
687
+ else if ( $sOptionType == 'multiple_select' ) {
688
+ }
689
+ }
690
+ $this->setOpt( $sOptionKey, $sOptionValue );
691
  }
692
+ return $this->savePluginOptions();
693
+ }
694
+
695
+ /**
696
+ * Should be over-ridden by each new class to handle upgrades.
697
+ *
698
+ * Called upon construction and after plugin options are initialized.
699
+ */
700
+ protected function updateHandler() {
701
+ if ( version_compare( $this->getVersion(), '3.0.0', '<' ) ) {
702
+ $oWpFunctions = $this->loadWpFunctionsProcessor();
703
+ $sKey = $this->doPluginPrefix( $this->getFeatureSlug().'_processor', '_' );
704
+ $oWpFunctions->deleteOption( $sKey );
705
  }
 
706
  }
707
 
708
+ /**
709
+ * @return boolean
710
+ */
711
+ public function hasEncryptOption() {
712
+ return function_exists( 'md5' );
713
+ // return extension_loaded( 'mcrypt' );
714
+ }
715
+
716
+ /**
717
+ * Prefixes an option key only if it's needed
718
+ *
719
+ * @param $sKey
720
+ * @return string
721
+ */
722
+ public function prefixOptionKey( $sKey ) {
723
+ return $this->doPluginPrefix( $sKey, '_' );
724
+ }
725
+
726
+ /**
727
+ * Will prefix and return any string with the unique plugin prefix.
728
+ *
729
+ * @param string $sSuffix
730
+ * @param string $sGlue
731
+ * @return string
732
+ */
733
+ public function doPluginPrefix( $sSuffix = '', $sGlue = '-' ) {
734
+ return $this->getController()->doPluginPrefix( $sSuffix, $sGlue );
735
+ }
736
+
737
+ /**
738
+ * @param string
739
+ * @return string
740
+ */
741
+ public function getOptionStoragePrefix() {
742
+ return $this->getController()->getOptionStoragePrefix();
743
+ }
744
+
745
+ /**
746
+ * @param string $insExistingListKey
747
+ * @param string $insFilterName
748
+ * @return array|false
749
+ */
750
+ protected function processIpFilter( $insExistingListKey, $insFilterName ) {
751
+ $aFilterIps = apply_filters( $insFilterName, array() );
752
+ if ( empty( $aFilterIps ) ) {
753
+ return false;
754
+ }
755
 
756
+ $aNewIps = array();
757
+ foreach( $aFilterIps as $mKey => $sValue ) {
758
+ if ( is_string( $mKey ) ) { //it's the IP
759
+ $sIP = $mKey;
760
+ $sLabel = $sValue;
761
+ }
762
+ else { //it's not an associative array, so the value is the IP
763
+ $sIP = $sValue;
764
+ $sLabel = '';
765
+ }
766
+ $aNewIps[ $sIP ] = $sLabel;
767
+ }
768
 
769
+ // now add and store the new IPs
770
+ $aExistingIpList = $this->getOpt( $insExistingListKey );
771
+ if ( !is_array( $aExistingIpList ) ) {
772
+ $aExistingIpList = array();
773
+ }
774
 
775
+ $oDp = $this->loadDataProcessor();
776
+ $nNewAddedCount = 0;
777
+ $aNewList = $oDp->Add_New_Raw_Ips( $aExistingIpList, $aNewIps, $nNewAddedCount );
778
+ if ( $nNewAddedCount > 0 ) {
779
+ $this->setOpt( $insExistingListKey, $aNewList );
780
+ }
781
  }
782
 
783
+ /**
784
+ */
785
+ public function displayFeatureConfigPage( ) {
 
 
 
 
 
 
 
 
 
786
 
787
+ if ( !apply_filters( $this->doPluginPrefix( 'has_permission_to_view' ), true ) ) {
788
+ $this->displayViewAccessRestrictedPage();
789
+ return;
790
+ }
 
 
 
 
 
791
 
792
+ // $aPluginSummaryData = apply_filters( $this->doPluginPrefix( 'get_feature_summary_data' ), array() );
793
+ $aData = array(
794
+ 'aSummaryData' => isset( $aPluginSummaryData ) ? $aPluginSummaryData : array()
795
+ );
796
+ $aData = array_merge( $this->getBaseDisplayData(), $aData );
797
+ $this->display( $aData );
798
+ }
799
+
800
+ /**
801
+ * @return bool
802
+ */
803
+ public function getIsCurrentPageConfig() {
804
+ $oWpFunctions = $this->loadWpFunctionsProcessor();
805
+ return $oWpFunctions->getCurrentWpAdminPage() == $this->doPluginPrefix( $this->getFeatureSlug() );
806
+ }
807
+
808
+ /**
809
+ */
810
+ public function displayViewAccessRestrictedPage( ) {
811
+ $aData = $this->getBaseDisplayData();
812
+ $this->display( $aData, 'access_restricted_index' );
813
+ }
814
+
815
+ /**
816
+ * @return array
817
+ */
818
+ protected function getBaseDisplayData() {
819
+ return array(
820
+ 'var_prefix' => $this->getController()->getOptionStoragePrefix(),
821
+ 'sPluginName' => $this->getController()->getHumanName(),
822
+ 'sFeatureName' => $this->getMainFeatureName(),
823
+ 'fShowAds' => $this->getIsShowMarketing(),
824
+ 'nonce_field' => $this->getController()->getPluginPrefix(),
825
+ 'sFeatureSlug' => $this->doPluginPrefix( $this->getFeatureSlug() ),
826
+ 'form_action' => 'admin.php?page='.$this->doPluginPrefix( $this->getFeatureSlug() ),
827
+ 'nOptionsPerRow' => 1,
828
+
829
+ 'aAllOptions' => $this->getOptions(),
830
+ 'all_options_input' => $this->collateAllFormInputsForAllOptions()
831
+ );
832
+ }
833
+
834
+ /**
835
+ * @return boolean
836
+ */
837
+ protected function getIsShowMarketing() {
838
+ return apply_filters( $this->doPluginPrefix( 'show_marketing' ), true );
839
+ }
840
+
841
+ /**
842
+ * @param array $aData
843
+ * @param string $sView
844
+ * @return bool
845
+ */
846
+ protected function display( $aData = array(), $sView = '' ) {
847
+
848
+ if ( empty( $sView ) ) {
849
+ $oWpFs = $this->loadFileSystemProcessor();
850
+ $sCustomViewSource = $this->getController()->getViewPath( $this->doPluginPrefix( 'config_'.$this->getFeatureSlug().'_index' ) );
851
+ $sNormalViewSource = $this->getController()->getViewPath( $this->doPluginPrefix( 'config_index' ) );
852
+ $sFile = $oWpFs->exists( $sCustomViewSource ) ? $sCustomViewSource : $sNormalViewSource;
853
+ }
854
+ else {
855
+ $sFile = $this->getController()->getViewPath( $this->doPluginPrefix( $sView ) );
856
+ }
857
 
858
+ if ( !is_file( $sFile ) ) {
859
+ echo "View not found: ".$sFile;
860
+ return false;
861
+ }
 
 
862
 
863
+ if ( count( $aData ) > 0 ) {
864
+ extract( $aData, EXTR_PREFIX_ALL, $this->getController()->getParentSlug() ); //slug being 'icwp'
865
+ }
 
 
 
866
 
867
+ ob_start();
868
+ include( $sFile );
869
+ $sContents = ob_get_contents();
870
+ ob_end_clean();
 
 
 
 
 
871
 
872
+ echo $sContents;
873
+ return true;
 
874
  }
875
 
876
+ /**
877
+ * @param string $sSnippet
878
+ * @return string
879
+ */
880
+ public function getViewSnippet( $sSnippet = '' ) {
881
+ return $this->getController()->getViewSnippet( $sSnippet );
882
  }
883
 
884
+ /**
885
+ * @param $sStatKey
886
+ */
887
+ public function doStatIncrement( $sStatKey ) {
888
+ $this->loadStatsProcessor();
889
+ ICWP_Stats_WPSF::DoStatIncrement( $sStatKey );
 
 
 
 
 
 
890
  }
 
891
 
892
+ /**
893
+ * @return ICWP_WPSF_Plugin_Controller
894
+ */
895
+ public function getController() {
896
+ return $this->oPluginController;
 
 
 
 
 
 
 
 
897
  }
 
898
  }
899
 
 
 
900
  endif;
901
 
902
+ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_FeatureHandler_Base_V2 { }
src/icwp-optionshandler-comments_filter.php CHANGED
@@ -21,11 +21,8 @@ if ( !class_exists('ICWP_WPSF_FeatureHandler_CommentsFilter') ):
21
 
22
  class ICWP_WPSF_FeatureHandler_CommentsFilter extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
- const DefaultCommentCooldown = 30; //seconds.
25
- const DefaultCommentExpire = 600; //seconds.
26
-
27
  /**
28
- * @var ICWP_WPSF_CommentsFilterProcessor
29
  */
30
  protected $oFeatureProcessor;
31
 
@@ -36,188 +33,323 @@ class ICWP_WPSF_FeatureHandler_CommentsFilter extends ICWP_WPSF_FeatureHandler_B
36
  }
37
 
38
  /**
39
- * @return ICWP_WPSF_CommentsFilterProcessor|null
40
  */
41
  protected function loadFeatureProcessor() {
42
  if ( !isset( $this->oFeatureProcessor ) ) {
43
- require_once( dirname(__FILE__).'/icwp-processor-commentsfilter.php' );
44
- $this->oFeatureProcessor = new ICWP_WPSF_CommentsFilterProcessor( $this );
45
  }
46
  return $this->oFeatureProcessor;
47
  }
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  /**
50
  * @return array
51
  */
52
  protected function getOptionsDefinitions() {
53
 
54
- $aBase = array(
55
- 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('SPAM Comments Protection Filter') ),
56
- 'section_options' => array(
57
- array(
58
- 'enable_comments_filter',
59
- '',
60
- 'N',
61
- 'checkbox',
62
- _wpsf__( 'Enable Comments Filter' ),
63
- _wpsf__( 'Enable (or Disable) The SPAM Comments Protection Filter Feature' ),
64
- sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('SPAM Comments Protection Filter') ),
65
- '<a href="http://icwp.io/3z" target="_blank">'._wpsf__( 'more info' ).'</a>'
66
- .' | <a href="http://icwp.io/wpsf04" target="_blank">'._wpsf__( 'blog' ).'</a>'
67
- )
68
- )
69
- );
70
-
71
- $aHumanSpam = array(
72
- 'section_title' => sprintf( _wpsf__( '%s Comment SPAM Protection Filter' ), _wpsf__('Human') ),
73
- 'section_options' => array(
74
- array(
75
- 'enable_comments_human_spam_filter',
76
- '',
77
- 'N',
78
- 'checkbox',
79
- _wpsf__( 'Human SPAM Filter' ),
80
- _wpsf__( 'Enable (or Disable) The Human SPAM Filter Feature.' ),
81
- _wpsf__( 'Scans the content of WordPress comments for keywords that are indicative of SPAM and marks the comment according to your preferred setting below.' ),
82
- '<a href="http://icwp.io/57" target="_blank">'._wpsf__( 'more info' ).'</a>'
83
- ),
84
- array(
85
- 'enable_comments_human_spam_filter_items',
86
- '',
87
- $this->getHumanSpamFilterItems( true ),
88
- $this->getHumanSpamFilterItems(),
89
- _wpsf__( 'Comment Filter Items' ),
90
- _wpsf__( 'Select The Items To Scan For SPAM' ),
91
- _wpsf__( 'When a user submits a comment, only the selected parts of the comment data will be scanned for SPAM content.' ).' '.sprintf( _wpsf__('Recommended: %s'), _wpsf__('All') ),
92
- '<a href="http://icwp.io/58" target="_blank">'._wpsf__( 'more info' ).'</a>'
93
- ),
94
- array(
95
- 'comments_default_action_human_spam',
96
- '',
97
- 'spam',
98
- $this->getSpamHandlingResponses(),
99
- _wpsf__( 'Default SPAM Action' ),
100
- _wpsf__( 'How To Categorise Comments When Identified To Be SPAM' ),
101
- sprintf( _wpsf__( 'When a comment is detected as being SPAM from %s, the comment will be categorised based on this setting.' ), '<span style"text-decoration:underline;">'._wpsf__('a human commenter').'</span>' ),
102
- '<a href="http://icwp.io/59" target="_blank">'._wpsf__( 'more info' ).'</a>'
103
- )
104
- ),
105
- );
106
-
107
- $aGasp = array(
108
- 'section_title' => sprintf( _wpsf__( '%s Comment SPAM Protection Filter' ), _wpsf__('Automatic Bot') ),
109
- 'section_options' => array(
110
- array(
111
- 'enable_comments_gasp_protection',
112
- '',
113
- 'Y',
114
- 'checkbox',
115
- _wpsf__( 'GASP Protection' ),
116
- _wpsf__( 'Add Growmap Anti Spambot Protection to your comments' ),
117
- _wpsf__( 'Taking the lead from the original GASP plugin for WordPress, we have extended it to include advanced spam-bot protection.' ),
118
- '<a href="http://icwp.io/3n" target="_blank">'._wpsf__( 'more info' ).'</a>'
119
- .' | <a href="http://icwp.io/2n" target="_blank">'._wpsf__( 'blog' ).'</a>'
120
- ),
121
- array(
122
- 'comments_default_action_spam_bot',
123
- '',
124
- 'trash',
125
- $this->getSpamHandlingResponses(),
126
- _wpsf__( 'Default SPAM Action' ),
127
- _wpsf__( 'How To Categorise Comments When Identified To Be SPAM' ),
128
- sprintf( _wpsf__( 'When a comment is detected as being SPAM from %s, the comment will be categorised based on this setting.' ), '<span style"text-decoration:underline;">'._wpsf__('an automatic bot').'</span>' ),
129
- '<a href="http://icwp.io/59" target="_blank">'._wpsf__( 'more info' ).'</a>'
130
- ),
131
- array(
132
- 'enable_comments_gasp_protection_for_logged_in',
133
- '',
134
- 'N',
135
- 'checkbox',
136
- _wpsf__( 'Include Logged-In Users' ),
137
- _wpsf__( 'You may also enable GASP for logged in users' ),
138
- _wpsf__( 'Since logged-in users would be expected to be vetted already, this is off by default.' )
139
- ),
140
- array(
141
- 'comments_cooldown_interval',
142
- '',
143
- '30',
144
- 'integer',
145
- _wpsf__( 'Comments Cooldown' ),
146
- _wpsf__( 'Limit posting comments to X seconds after the page has loaded' ),
147
- _wpsf__( "By forcing a comments cooldown period, you restrict a Spambot's ability to post mutliple times to your posts." ),
148
- '<a href="http://icwp.io/3o" target="_blank">'._wpsf__( 'more info' ).'</a>'
149
- ),
150
- array(
151
- 'comments_token_expire_interval',
152
- '',
153
- '600',
154
- 'integer',
155
- _wpsf__( 'Comment Token Expire' ),
156
- _wpsf__( 'A visitor has X seconds within which to post a comment' ),
157
- _wpsf__( "Default: 600 seconds (10 minutes). Each visitor is given a unique 'Token' so they can comment. This restricts spambots, but we need to force these tokens to expire and at the same time not bother the visitors." ),
158
- '<a href="http://icwp.io/3o" target="_blank">'._wpsf__( 'more info' ).'</a>'
159
-
160
- )
161
- )
162
- );
163
-
164
- $aCustomMessages = array(
165
- 'section_title' => sprintf( _wpsf__( 'Customize Messages Shown To User' ), _wpsf__('Automatic Bot') ),
166
- 'section_options' => array(
167
- array(
168
- 'custom_message_checkbox',
169
- '',
170
- _wpsf__( "I'm not a spammer" ),
171
- 'text',
172
- _wpsf__( 'Custom Checkbox Message' ),
173
- _wpsf__( 'If you want a custom checkbox message, please provide this here' ),
174
- _wpsf__( "You can customise the message beside the checkbox." )
175
- .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please check the box to confirm you're not a spammer") ),
176
- '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
177
- ),
178
- array(
179
- 'custom_message_alert',
180
- '',
181
- _wpsf__( "Please check the box to confirm you're not a spammer" ),
182
- 'text',
183
- _wpsf__( 'Custom Alert Message' ),
184
- _wpsf__( 'If you want a custom alert message, please provide this here' ),
185
- _wpsf__( "This alert message is displayed when a visitor attempts to submit a comment without checking the box." )
186
- .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please check the box to confirm you're not a spammer") ),
187
- '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
188
- ),
189
- array(
190
- 'custom_message_comment_wait',
191
- '',
192
- _wpsf__( "Please wait %s seconds before posting your comment" ),
193
- 'text',
194
- _wpsf__( 'Custom Wait Message' ),
195
- _wpsf__( 'If you want a custom submit-button wait message, please provide this here.' ),
196
- _wpsf__( "Where you see the '%s' this will be the number of seconds. You must ensure you include 1, and only 1, of these." )
197
- .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__('Please wait %s seconds before posting your comment') ),
198
- '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
199
- ),
200
- array(
201
- 'custom_message_comment_reload',
202
- '',
203
- _wpsf__( "Please reload this page to post a comment" ),
204
- 'text',
205
- _wpsf__( 'Custom Reload Message' ),
206
- _wpsf__( 'If you want a custom message when the comment token has expired, please provide this here.' ),
207
- _wpsf__( 'This message is displayed on the submit-button when the comment token is expired' )
208
- .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please reload this page to post a comment") ),
209
- '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
210
- )
211
- )
212
- );
213
-
214
- $aOptionsDefinitions = array(
215
- $aBase,
216
- $aHumanSpam,
217
- $aGasp,
218
- $aCustomMessages
219
- );
220
- return $aOptionsDefinitions;
221
  }
222
 
223
  /**
@@ -225,58 +357,30 @@ class ICWP_WPSF_FeatureHandler_CommentsFilter extends ICWP_WPSF_FeatureHandler_B
225
  */
226
  protected function doPrePluginOptionsSave() {
227
 
228
- $nCommentCooldown = $this->getOpt( 'comments_cooldown_interval' );
229
- if ( $nCommentCooldown < 0 ) {
230
- $nCommentCooldown = 0;
231
  }
232
 
233
- $nCommentTokenExpire = $this->getOpt( 'comments_token_expire_interval' );
234
- if ( $nCommentTokenExpire < 0 ) {
235
- $nCommentTokenExpire = 0;
236
  }
237
 
238
- if ( $nCommentTokenExpire != 0 && $nCommentCooldown > $nCommentTokenExpire ) {
239
- $nCommentCooldown = self::DefaultCommentCooldown;
240
- $nCommentTokenExpire = self::DefaultCommentExpire;
241
  }
242
- $this->setOpt( 'comments_cooldown_interval', $nCommentCooldown );
243
- $this->setOpt( 'comments_token_expire_interval', $nCommentTokenExpire );
244
 
245
  $aCommentsFilters = $this->getOpt( 'enable_comments_human_spam_filter_items' );
246
- if ( empty($aCommentsFilters) || !is_array( $aCommentsFilters ) ) {
247
- $this->setOpt( 'enable_comments_human_spam_filter_items', $this->getHumanSpamFilterItems( true ) );
248
  }
249
  }
250
 
251
  /**
252
- * @return array
253
- */
254
- protected function getSpamHandlingResponses() {
255
- return array( 'select',
256
- array( 0, _wpsf__( 'Mark As Pending Moderation' ) ),
257
- array( 'spam', _wpsf__( 'Mark As SPAM' ) ),
258
- array( 'trash', _wpsf__( 'Move To Trash' ) ),
259
- array( 'reject', _wpsf__( 'Reject And Redirect' ) )
260
- );
261
- }
262
-
263
- /**
264
- *
265
  */
266
- protected function getHumanSpamFilterItems( $fAsDefaults = false ) {
267
- $aFilterItems = array( 'type' => 'multiple_select',
268
- 'author_name' => _wpsf__('Author Name'),
269
- 'author_email' => _wpsf__('Author Email'),
270
- 'comment_content' => _wpsf__('Comment Content'),
271
- 'url' => _wpsf__('URL'),
272
- 'ip_address' => _wpsf__('IP Address'),
273
- 'user_agent' => _wpsf__('Browser User Agent')
274
- );
275
- if ( $fAsDefaults ) {
276
- unset($aFilterItems['type']);
277
- return array_keys($aFilterItems);
278
- }
279
- return $aFilterItems;
280
  }
281
  }
282
 
21
 
22
  class ICWP_WPSF_FeatureHandler_CommentsFilter extends ICWP_WPSF_FeatureHandler_Base {
23
 
 
 
 
24
  /**
25
+ * @var ICWP_WPSF_Processor_CommentsFilter
26
  */
27
  protected $oFeatureProcessor;
28
 
33
  }
34
 
35
  /**
36
+ * @return ICWP_WPSF_Processor_CommentsFilter|null
37
  */
38
  protected function loadFeatureProcessor() {
39
  if ( !isset( $this->oFeatureProcessor ) ) {
40
+ require_once( $this->getController()->getSourceDir().sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) );
41
+ $this->oFeatureProcessor = new ICWP_WPSF_Processor_CommentsFilter( $this );
42
  }
43
  return $this->oFeatureProcessor;
44
  }
45
 
46
+ /**
47
+ * @param array $aOptionsParams
48
+ * @return array
49
+ * @throws Exception
50
+ */
51
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
52
+
53
+ $sSectionSlug = $aOptionsParams['section_slug'];
54
+ switch( $aOptionsParams['section_slug'] ) {
55
+
56
+ case 'section_enable_plugin_feature_spam_comments_protection_filter' :
57
+ $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('SPAM Comments Protection Filter') );
58
+ break;
59
+
60
+ case 'section_enable_human_comment_spam_protection_filter' :
61
+ $sTitle = sprintf( _wpsf__( '%s Comment SPAM Protection Filter' ), _wpsf__('Human') );
62
+ break;
63
+
64
+ case 'section_enable_automatic_bot_comment_spam_protection_filter' :
65
+ $sTitle = sprintf( _wpsf__( '%s Comment SPAM Protection Filter' ), _wpsf__('Automatic Bot') );
66
+ break;
67
+
68
+ case 'section_customize_messages_shown_to_user' :
69
+ $sTitle = _wpsf__( 'Customize Messages Shown To User' );
70
+ break;
71
+
72
+ default:
73
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
74
+ }
75
+ $aOptionsParams['section_title'] = $sTitle;
76
+ return $aOptionsParams;
77
+ }
78
+
79
+ /**
80
+ * @param array $aOptionsParams
81
+ * @return array
82
+ * @throws Exception
83
+ */
84
+ protected function loadStrings_Options( $aOptionsParams ) {
85
+
86
+ $sKey = $aOptionsParams['key'];
87
+ switch( $sKey ) {
88
+
89
+ case 'enable_comments_filter' :
90
+ $sName = sprintf( _wpsf__( 'Enable %s' ), _wpsf__('Comments Filter') );
91
+ $sSummary = _wpsf__( 'Enable (or Disable) The SPAM Comments Protection Filter Feature' );
92
+ $sDescription = sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('SPAM Comments Protection Filter') );
93
+ break;
94
+
95
+ case 'enable_comments_human_spam_filter' :
96
+ $sName = _wpsf__( 'Human SPAM Filter' );
97
+ $sSummary = _wpsf__( 'Enable (or Disable) The Human SPAM Filter Feature.' );
98
+ $sDescription = _wpsf__( 'Scans the content of WordPress comments for keywords that are indicative of SPAM and marks the comment according to your preferred setting below.' );
99
+ break;
100
+
101
+ case 'enable_comments_human_spam_filter_items' :
102
+ $sName = _wpsf__( 'Comment Filter Items' );
103
+ $sSummary = _wpsf__( 'Select The Items To Scan For SPAM' );
104
+ $sDescription = _wpsf__( 'When a user submits a comment, only the selected parts of the comment data will be scanned for SPAM content.' ).' '.sprintf( _wpsf__('Recommended: %s'), _wpsf__('All') );
105
+ break;
106
+
107
+ case 'comments_default_action_human_spam' :
108
+ $sName = _wpsf__( 'Default SPAM Action' );
109
+ $sSummary = _wpsf__( 'How To Categorise Comments When Identified To Be SPAM' );
110
+ $sDescription = sprintf( _wpsf__( 'When a comment is detected as being SPAM from %s, the comment will be categorised based on this setting.' ), '<span style"text-decoration:underline;">'._wpsf__('a human commenter').'</span>' );
111
+ break;
112
+
113
+ case 'enable_comments_gasp_protection' :
114
+ $sName = _wpsf__( 'GASP Protection' );
115
+ $sSummary = _wpsf__( 'Add Growmap Anti Spambot Protection to your comments' );
116
+ $sDescription = _wpsf__( 'Taking the lead from the original GASP plugin for WordPress, we have extended it to include advanced spam-bot protection.' );
117
+ break;
118
+
119
+ case 'comments_default_action_spam_bot' :
120
+ $sName = _wpsf__( 'Default SPAM Action' );
121
+ $sSummary = _wpsf__( 'How To Categorise Comments When Identified To Be SPAM' );
122
+ $sDescription = sprintf( _wpsf__( 'When a comment is detected as being SPAM from %s, the comment will be categorised based on this setting.' ), '<span style"text-decoration:underline;">'._wpsf__('an automatic bot').'</span>' );
123
+ break;
124
+
125
+ case 'enable_comments_gasp_protection_for_logged_in' :
126
+ $sName = _wpsf__( 'Include Logged-In Users' );
127
+ $sSummary = _wpsf__( 'You may also enable GASP for logged in users' );
128
+ $sDescription = _wpsf__( 'Since logged-in users would be expected to be vetted already, this is off by default.' );
129
+ break;
130
+
131
+ case 'comments_cooldown_interval' :
132
+ $sName = _wpsf__( 'Comments Cooldown' );
133
+ $sSummary = _wpsf__( 'Limit posting comments to X seconds after the page has loaded' );
134
+ $sDescription = _wpsf__( "By forcing a comments cooldown period, you restrict a Spambot's ability to post multiple times to your posts." );
135
+ break;
136
+
137
+ case 'comments_token_expire_interval' :
138
+ $sName = _wpsf__( 'Comment Token Expire' );
139
+ $sSummary = _wpsf__( 'A visitor has X seconds within which to post a comment' );
140
+ $sDescription = _wpsf__( "Default: 600 seconds (10 minutes). Each visitor is given a unique 'Token' so they can comment. This restricts spambots, but we need to force these tokens to expire and at the same time not bother the visitors." );
141
+ break;
142
+
143
+ case 'custom_message_checkbox' :
144
+ $sName = _wpsf__( 'Custom Checkbox Message' );
145
+ $sSummary = _wpsf__( 'If you want a custom checkbox message, please provide this here' );
146
+ $sDescription = _wpsf__( "You can customise the message beside the checkbox." )
147
+ .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please check the box to confirm you're not a spammer") );
148
+ break;
149
+
150
+ case 'custom_message_alert' :
151
+ $sName = _wpsf__( 'Custom Alert Message' );
152
+ $sSummary = _wpsf__( 'If you want a custom alert message, please provide this here' );
153
+ $sDescription = _wpsf__( "This alert message is displayed when a visitor attempts to submit a comment without checking the box." )
154
+ .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please check the box to confirm you're not a spammer") );
155
+ break;
156
+
157
+ case 'custom_message_comment_wait' :
158
+ $sName = _wpsf__( 'Custom Wait Message' );
159
+ $sSummary = _wpsf__( 'If you want a custom submit-button wait message, please provide this here.' );
160
+ $sDescription = _wpsf__( "Where you see the '%s' this will be the number of seconds. You must ensure you include 1, and only 1, of these." )
161
+ .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__('Please wait %s seconds before posting your comment') );
162
+ break;
163
+
164
+ case 'custom_message_comment_reload' :
165
+ $sName = _wpsf__( 'Custom Reload Message' );
166
+ $sSummary = _wpsf__( 'If you want a custom message when the comment token has expired, please provide this here.' );
167
+ $sDescription = _wpsf__( 'This message is displayed on the submit-button when the comment token is expired' )
168
+ .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please reload this page to post a comment") );
169
+ break;
170
+
171
+ default:
172
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
173
+ }
174
+
175
+ $aOptionsParams['name'] = $sName;
176
+ $aOptionsParams['summary'] = $sSummary;
177
+ $aOptionsParams['description'] = $sDescription;
178
+ return $aOptionsParams;
179
+ }
180
+
181
  /**
182
  * @return array
183
  */
184
  protected function getOptionsDefinitions() {
185
 
186
+ // $aBase = array(
187
+ // 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('SPAM Comments Protection Filter') ),
188
+ // 'section_options' => array(
189
+ // array(
190
+ // 'enable_comments_filter',
191
+ // '',
192
+ // 'N',
193
+ // 'checkbox',
194
+ // sprintf( _wpsf__( 'Enable %s' ), _wpsf__('Comments Filter') ),
195
+ // _wpsf__( 'Enable (or Disable) The SPAM Comments Protection Filter Feature' ),
196
+ // sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('SPAM Comments Protection Filter') ),
197
+ // '<a href="http://icwp.io/3z" target="_blank">'._wpsf__( 'more info' ).'</a>'
198
+ // .' | <a href="http://icwp.io/wpsf04" target="_blank">'._wpsf__( 'blog' ).'</a>'
199
+ // )
200
+ // )
201
+ // );
202
+ //
203
+ // $aHumanSpam = array(
204
+ // 'section_title' => sprintf( _wpsf__( '%s Comment SPAM Protection Filter' ), _wpsf__('Human') ),
205
+ // 'section_options' => array(
206
+ // array(
207
+ // 'enable_comments_human_spam_filter',
208
+ // '',
209
+ // 'N',
210
+ // 'checkbox',
211
+ // _wpsf__( 'Human SPAM Filter' ),
212
+ // _wpsf__( 'Enable (or Disable) The Human SPAM Filter Feature.' ),
213
+ // _wpsf__( 'Scans the content of WordPress comments for keywords that are indicative of SPAM and marks the comment according to your preferred setting below.' ),
214
+ // '<a href="http://icwp.io/57" target="_blank">'._wpsf__( 'more info' ).'</a>'
215
+ // ),
216
+ // array(
217
+ // 'enable_comments_human_spam_filter_items',
218
+ // '',
219
+ // $this->getHumanSpamFilterItems( true ),
220
+ // $this->getHumanSpamFilterItems(),
221
+ // _wpsf__( 'Comment Filter Items' ),
222
+ // _wpsf__( 'Select The Items To Scan For SPAM' ),
223
+ // _wpsf__( 'When a user submits a comment, only the selected parts of the comment data will be scanned for SPAM content.' ).' '.sprintf( _wpsf__('Recommended: %s'), _wpsf__('All') ),
224
+ // '<a href="http://icwp.io/58" target="_blank">'._wpsf__( 'more info' ).'</a>'
225
+ // ),
226
+ // array(
227
+ // 'comments_default_action_human_spam',
228
+ // '',
229
+ // 'spam',
230
+ // $this->getSpamHandlingResponses(),
231
+ // _wpsf__( 'Default SPAM Action' ),
232
+ // _wpsf__( 'How To Categorise Comments When Identified To Be SPAM' ),
233
+ // sprintf( _wpsf__( 'When a comment is detected as being SPAM from %s, the comment will be categorised based on this setting.' ), '<span style"text-decoration:underline;">'._wpsf__('a human commenter').'</span>' ),
234
+ // '<a href="http://icwp.io/59" target="_blank">'._wpsf__( 'more info' ).'</a>'
235
+ // )
236
+ // ),
237
+ // );
238
+ //
239
+ // $aGasp = array(
240
+ // 'section_title' => sprintf( _wpsf__( '%s Comment SPAM Protection Filter' ), _wpsf__('Automatic Bot') ),
241
+ // 'section_options' => array(
242
+ // array(
243
+ // 'enable_comments_gasp_protection',
244
+ // '',
245
+ // 'Y',
246
+ // 'checkbox',
247
+ // _wpsf__( 'GASP Protection' ),
248
+ // _wpsf__( 'Add Growmap Anti Spambot Protection to your comments' ),
249
+ // _wpsf__( 'Taking the lead from the original GASP plugin for WordPress, we have extended it to include advanced spam-bot protection.' ),
250
+ // '<a href="http://icwp.io/3n" target="_blank">'._wpsf__( 'more info' ).'</a>'
251
+ // .' | <a href="http://icwp.io/2n" target="_blank">'._wpsf__( 'blog' ).'</a>'
252
+ // ),
253
+ // array(
254
+ // 'comments_default_action_spam_bot',
255
+ // '',
256
+ // 'trash',
257
+ // $this->getSpamHandlingResponses(),
258
+ // _wpsf__( 'Default SPAM Action' ),
259
+ // _wpsf__( 'How To Categorise Comments When Identified To Be SPAM' ),
260
+ // sprintf( _wpsf__( 'When a comment is detected as being SPAM from %s, the comment will be categorised based on this setting.' ), '<span style"text-decoration:underline;">'._wpsf__('an automatic bot').'</span>' ),
261
+ // '<a href="http://icwp.io/59" target="_blank">'._wpsf__( 'more info' ).'</a>'
262
+ // ),
263
+ // array(
264
+ // 'enable_comments_gasp_protection_for_logged_in',
265
+ // '',
266
+ // 'N',
267
+ // 'checkbox',
268
+ // _wpsf__( 'Include Logged-In Users' ),
269
+ // _wpsf__( 'You may also enable GASP for logged in users' ),
270
+ // _wpsf__( 'Since logged-in users would be expected to be vetted already, this is off by default.' )
271
+ // ),
272
+ // array(
273
+ // 'comments_cooldown_interval',
274
+ // '',
275
+ // '30',
276
+ // 'integer',
277
+ // _wpsf__( 'Comments Cooldown' ),
278
+ // _wpsf__( 'Limit posting comments to X seconds after the page has loaded' ),
279
+ // _wpsf__( "By forcing a comments cooldown period, you restrict a Spambot's ability to post mutliple times to your posts." ),
280
+ // '<a href="http://icwp.io/3o" target="_blank">'._wpsf__( 'more info' ).'</a>'
281
+ // ),
282
+ // array(
283
+ // 'comments_token_expire_interval',
284
+ // '',
285
+ // '600',
286
+ // 'integer',
287
+ // _wpsf__( 'Comment Token Expire' ),
288
+ // _wpsf__( 'A visitor has X seconds within which to post a comment' ),
289
+ // _wpsf__( "Default: 600 seconds (10 minutes). Each visitor is given a unique 'Token' so they can comment. This restricts spambots, but we need to force these tokens to expire and at the same time not bother the visitors." ),
290
+ // '<a href="http://icwp.io/3o" target="_blank">'._wpsf__( 'more info' ).'</a>'
291
+ //
292
+ // )
293
+ // )
294
+ // );
295
+ //
296
+ // $aCustomMessages = array(
297
+ // 'section_title' => sprintf( _wpsf__( 'Customize Messages Shown To User' ), _wpsf__('Automatic Bot') ),
298
+ // 'section_options' => array(
299
+ // array(
300
+ // 'custom_message_checkbox',
301
+ // '',
302
+ // _wpsf__( "I'm not a spammer" ),
303
+ // 'text',
304
+ // _wpsf__( 'Custom Checkbox Message' ),
305
+ // _wpsf__( 'If you want a custom checkbox message, please provide this here' ),
306
+ // _wpsf__( "You can customise the message beside the checkbox." )
307
+ // .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please check the box to confirm you're not a spammer") ),
308
+ // '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
309
+ // ),
310
+ // array(
311
+ // 'custom_message_alert',
312
+ // '',
313
+ // _wpsf__( "Please check the box to confirm you're not a spammer" ),
314
+ // 'text',
315
+ // _wpsf__( 'Custom Alert Message' ),
316
+ // _wpsf__( 'If you want a custom alert message, please provide this here' ),
317
+ // _wpsf__( "This alert message is displayed when a visitor attempts to submit a comment without checking the box." )
318
+ // .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please check the box to confirm you're not a spammer") ),
319
+ // '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
320
+ // ),
321
+ // array(
322
+ // 'custom_message_comment_wait',
323
+ // '',
324
+ // _wpsf__( "Please wait %s seconds before posting your comment" ),
325
+ // 'text',
326
+ // _wpsf__( 'Custom Wait Message' ),
327
+ // _wpsf__( 'If you want a custom submit-button wait message, please provide this here.' ),
328
+ // _wpsf__( "Where you see the '%s' this will be the number of seconds. You must ensure you include 1, and only 1, of these." )
329
+ // .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__('Please wait %s seconds before posting your comment') ),
330
+ // '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
331
+ // ),
332
+ // array(
333
+ // 'custom_message_comment_reload',
334
+ // '',
335
+ // _wpsf__( "Please reload this page to post a comment" ),
336
+ // 'text',
337
+ // _wpsf__( 'Custom Reload Message' ),
338
+ // _wpsf__( 'If you want a custom message when the comment token has expired, please provide this here.' ),
339
+ // _wpsf__( 'This message is displayed on the submit-button when the comment token is expired' )
340
+ // .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please reload this page to post a comment") ),
341
+ // '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
342
+ // )
343
+ // )
344
+ // );
345
+ //
346
+ // $aOptionsDefinitions = array(
347
+ // $aBase,
348
+ // $aHumanSpam,
349
+ // $aGasp,
350
+ // $aCustomMessages
351
+ // );
352
+ // return $aOptionsDefinitions;
353
  }
354
 
355
  /**
357
  */
358
  protected function doPrePluginOptionsSave() {
359
 
360
+ if ( $this->getOpt( 'comments_cooldown_interval' ) < 0 ) {
361
+ $this->getOptionsVo()->resetOptToDefault( 'comments_cooldown_interval' );
 
362
  }
363
 
364
+ if ( $this->getOpt( 'comments_token_expire_interval' ) < 0 ) {
365
+ $this->getOptionsVo()->resetOptToDefault( 'comments_token_expire_interval' );
 
366
  }
367
 
368
+ if ( $this->getOpt( 'comments_token_expire_interval' ) != 0 && $this->getOpt( 'comments_cooldown_interval' ) > $this->getOpt( 'comments_token_expire_interval' ) ) {
369
+ $this->getOptionsVo()->resetOptToDefault( 'comments_cooldown_interval' );
370
+ $this->getOptionsVo()->resetOptToDefault( 'comments_token_expire_interval' );
371
  }
 
 
372
 
373
  $aCommentsFilters = $this->getOpt( 'enable_comments_human_spam_filter_items' );
374
+ if ( empty( $aCommentsFilters ) || !is_array( $aCommentsFilters ) ) {
375
+ $this->getOptionsVo()->resetOptToDefault( 'enable_comments_human_spam_filter_items' );
376
  }
377
  }
378
 
379
  /**
380
+ * @return string
 
 
 
 
 
 
 
 
 
 
 
 
381
  */
382
+ public function getCommentsFilterTableName() {
383
+ return $this->doPluginPrefix( $this->getOpt( 'spambot_comments_filter_table_name' ), '_' );
 
 
 
 
 
 
 
 
 
 
 
 
384
  }
385
  }
386
 
src/icwp-optionshandler-email.php CHANGED
@@ -22,7 +22,7 @@ if ( !class_exists('ICWP_WPSF_FeatureHandler_Email') ):
22
  class ICWP_WPSF_FeatureHandler_Email extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
  /**
25
- * @var ICWP_WPSF_EmailProcessor
26
  */
27
  protected $oFeatureProcessor;
28
 
@@ -32,55 +32,73 @@ class ICWP_WPSF_FeatureHandler_Email extends ICWP_WPSF_FeatureHandler_Base {
32
  public function __construct( $oPluginVo ) {
33
  $this->sFeatureName = _wpsf__('Email');
34
  $this->sFeatureSlug = 'email';
35
- $this->fShowFeatureMenuItem = false;
36
  parent::__construct( $oPluginVo );
37
  }
38
 
39
  /**
40
- * @return ICWP_WPSF_EmailProcessor|null
41
  */
42
  protected function loadFeatureProcessor() {
43
  if ( !isset( $this->oFeatureProcessor ) ) {
44
- require_once( dirname(__FILE__).'/icwp-processor-email.php' );
45
- $this->oFeatureProcessor = new ICWP_WPSF_EmailProcessor( $this );
46
  }
47
  return $this->oFeatureProcessor;
48
  }
49
 
50
  /**
 
51
  * @return array
 
52
  */
53
- protected function getOptionsDefinitions() {
54
- $aEmail = array(
55
- 'section_title' => _wpsf__( 'Email Options' ),
56
- 'section_options' => array(
57
- array(
58
- 'block_send_email_address',
59
- '',
60
- '',
61
- 'email',
62
- _wpsf__( 'Report Email' ),
63
- _wpsf__( 'Where to send email reports' ),
64
- _wpsf__( 'If this is empty, it will default to the blog admin email address' )
65
- ),
66
- array(
67
- 'send_email_throttle_limit',
68
- '',
69
- '10',
70
- 'integer',
71
- _wpsf__( 'Email Throttle Limit' ),
72
- _wpsf__( 'Limit Emails Per Second' ),
73
- _wpsf__( 'You throttle emails sent by this plugin by limiting the number of emails sent every second. This is useful in case you get hit by a bot attack. Zero (0) turns this off. Suggested: 10' )
74
- )
75
- )
76
- );
77
-
78
- $aOptionsDefinitions = array(
79
- $aEmail
80
- );
81
- return $aOptionsDefinitions;
82
  }
83
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  /**
85
  * This is the point where you would want to do any options verification
86
  */
22
  class ICWP_WPSF_FeatureHandler_Email extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
  /**
25
+ * @var ICWP_WPSF_Processor_Email
26
  */
27
  protected $oFeatureProcessor;
28
 
32
  public function __construct( $oPluginVo ) {
33
  $this->sFeatureName = _wpsf__('Email');
34
  $this->sFeatureSlug = 'email';
 
35
  parent::__construct( $oPluginVo );
36
  }
37
 
38
  /**
39
+ * @return ICWP_WPSF_Processor_Email|null
40
  */
41
  protected function loadFeatureProcessor() {
42
  if ( !isset( $this->oFeatureProcessor ) ) {
43
+ require_once( $this->getController()->getSourceDir( sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) ) );
44
+ $this->oFeatureProcessor = new ICWP_WPSF_Processor_Email( $this );
45
  }
46
  return $this->oFeatureProcessor;
47
  }
48
 
49
  /**
50
+ * @param array $aOptionsParams
51
  * @return array
52
+ * @throws Exception
53
  */
54
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
55
+
56
+ $sSectionSlug = $aOptionsParams['section_slug'];
57
+ switch( $aOptionsParams['section_slug'] ) {
58
+
59
+ case 'section_email_options' :
60
+ $sTitle = _wpsf__( 'Email Options' );
61
+ break;
62
+
63
+ default:
64
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
65
+ }
66
+ $aOptionsParams['section_title'] = $sTitle;
67
+ return $aOptionsParams;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
+
70
+ /**
71
+ * @param array $aOptionsParams
72
+ * @return array
73
+ * @throws Exception
74
+ */
75
+ protected function loadStrings_Options( $aOptionsParams ) {
76
+
77
+ $sKey = $aOptionsParams['key'];
78
+ switch( $sKey ) {
79
+
80
+ case 'block_send_email_address' :
81
+ $sName = _wpsf__( 'Report Email' );
82
+ $sSummary = _wpsf__( 'Where to send email reports' );
83
+ $sDescription = _wpsf__( 'If this is empty, it will default to the blog admin email address.' );
84
+ break;
85
+
86
+ case 'send_email_throttle_limit' :
87
+ $sName = _wpsf__( 'Email Throttle Limit' );
88
+ $sSummary = _wpsf__( 'Limit Emails Per Second' );
89
+ $sDescription = _wpsf__( 'You throttle emails sent by this plugin by limiting the number of emails sent every second. This is useful in case you get hit by a bot attack. Zero (0) turns this off. Suggested: 10' );
90
+ break;
91
+
92
+ default:
93
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
94
+ }
95
+
96
+ $aOptionsParams['name'] = $sName;
97
+ $aOptionsParams['summary'] = $sSummary;
98
+ $aOptionsParams['description'] = $sDescription;
99
+ return $aOptionsParams;
100
+ }
101
+
102
  /**
103
  * This is the point where you would want to do any options verification
104
  */
src/icwp-optionshandler-firewall.php CHANGED
@@ -22,7 +22,7 @@ if ( !class_exists('ICWP_WPSF_FeatureHandler_Firewall') ):
22
  class ICWP_WPSF_FeatureHandler_Firewall extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
  /**
25
- * @var ICWP_WPSF_FirewallProcessor
26
  */
27
  protected $oFeatureProcessor;
28
 
@@ -33,12 +33,12 @@ class ICWP_WPSF_FeatureHandler_Firewall extends ICWP_WPSF_FeatureHandler_Base {
33
  }
34
 
35
  /**
36
- * @return ICWP_WPSF_FirewallProcessor|null
37
  */
38
  protected function loadFeatureProcessor() {
39
  if ( !isset( $this->oFeatureProcessor ) ) {
40
- require_once( dirname(__FILE__).'/icwp-processor-firewall.php' );
41
- $this->oFeatureProcessor = new ICWP_WPSF_FirewallProcessor( $this );
42
  }
43
  return $this->oFeatureProcessor;
44
  }
@@ -75,235 +75,188 @@ class ICWP_WPSF_FeatureHandler_Firewall extends ICWP_WPSF_FeatureHandler_Base {
75
  }
76
 
77
  /**
 
78
  * @return array
 
79
  */
80
- protected function getOptionsDefinitions() {
81
- $aFirewallBase = array(
82
- 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('WordPress Firewall') ),
83
- 'section_options' => array(
84
- array(
85
- 'enable_firewall',
86
- '',
87
- 'N',
88
- 'checkbox',
89
- _wpsf__( 'Enable Firewall' ),
90
- _wpsf__( 'Enable (or Disable) The WordPress Firewall Feature' ),
91
- sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('WordPress Firewall') ),
92
- '<a href="http://icwp.io/43" target="_blank">'._wpsf__( 'more info' ).'</a>'
93
- .' | <a href="http://icwp.io/wpsf01" target="_blank">'._wpsf__( 'blog' ).'</a>'
94
- )
95
- )
96
- );
97
- $aBlockTypesSection = array(
98
- 'section_title' => _wpsf__( 'Firewall Blocking Options' ),
99
- 'section_options' => array(
100
- array(
101
- 'include_cookie_checks',
102
- '',
103
- 'N',
104
- 'checkbox',
105
- _wpsf__( 'Include Cookies' ),
106
- _wpsf__( 'Also Test Cookie Values In Firewall Tests' ),
107
- _wpsf__( 'The firewall tests GET and POST, but with this option checked it will also COOKIE values.' )
108
- ),
109
- array(
110
- 'block_dir_traversal',
111
- '',
112
- 'Y',
113
- 'checkbox',
114
- _wpsf__( 'Directory Traversals' ),
115
- _wpsf__( 'Block Directory Traversals' ),
116
- _wpsf__( 'This will block directory traversal paths in in application parameters (e.g. ../, ../../etc/passwd, etc.).' )
117
- ),
118
- array(
119
- 'block_sql_queries',
120
- '',
121
- 'Y',
122
- 'checkbox',
123
- _wpsf__( 'SQL Queries' ),
124
- _wpsf__( 'Block SQL Queries' ),
125
- _wpsf__( 'This will block sql in application parameters (e.g. union select, concat(, /**/, etc.).' )
126
- ),
127
- array(
128
- 'block_wordpress_terms',
129
- '',
130
- 'N',
131
- 'checkbox',
132
- _wpsf__( 'WordPress Terms' ),
133
- _wpsf__( 'Block WordPress Specific Terms' ),
134
- _wpsf__( 'This will block WordPress specific terms in application parameters (wp_, user_login, etc.).' )
135
- ),
136
- array(
137
- 'block_field_truncation',
138
- '',
139
- 'Y',
140
- 'checkbox',
141
- _wpsf__( 'Field Truncation' ),
142
- _wpsf__( 'Block Field Truncation Attacks' ),
143
- _wpsf__( 'This will block field truncation attacks in application parameters.' )
144
- ),
145
- array(
146
- 'block_php_code',
147
- '',
148
- 'N',
149
- 'checkbox',
150
- _wpsf__( 'PHP Code' ),
151
- sprintf( _wpsf__( 'Block %s' ), _wpsf__( 'PHP Code Includes' ) ),
152
- _wpsf__( 'This will block any data that appears to try and include PHP files.' )
153
- .'<br />'. _wpsf__( 'Will probably block saving within the Plugin/Theme file editors.' )
154
- ),
155
- array(
156
- 'block_exe_file_uploads',
157
- '',
158
- 'N',
159
- 'checkbox',
160
- _wpsf__( 'Exe File Uploads' ),
161
- _wpsf__( 'Block Executable File Uploads' ),
162
- _wpsf__( 'This will block executable file uploads (.php, .exe, etc.).' )
163
- ),
164
- array(
165
- 'block_leading_schema',
166
- '',
167
- 'N',
168
- 'checkbox',
169
- _wpsf__( 'Leading Schemas' ),
170
- _wpsf__( 'Block Leading Schemas (HTTPS / HTTP)' ),
171
- _wpsf__( 'This will block leading schemas http:// and https:// in application parameters (off by default; may cause problems with other plugins).' )
172
- )
173
- ),
174
- );
175
- $aRedirectOptions = array( 'select',
176
- array( 'redirect_die_message', _wpsf__( 'Die With Message' ) ),
177
- array( 'redirect_die', _wpsf__( 'Die' ) ),
178
- array( 'redirect_home', _wpsf__( 'Redirect To Home Page' ) ),
179
- array( 'redirect_404', _wpsf__( 'Return 404' ) ),
180
- );
181
- $aBlockSection = array(
182
- 'section_title' => _wpsf__( 'Choose Firewall Block Response' ),
183
- 'section_options' => array(
184
- array(
185
- 'block_response',
186
- '',
187
- 'none',
188
- $aRedirectOptions,
189
- _wpsf__( 'Block Response' ),
190
- _wpsf__( 'Choose how the firewall responds when it blocks a request' ),
191
- _wpsf__( 'We recommend dying with a message so you know what might have occurred when the firewall blocks you' )
192
- ),
193
- array(
194
- 'block_send_email',
195
- '',
196
- 'N',
197
- 'checkbox',
198
- _wpsf__( 'Send Email Report' ),
199
- _wpsf__( 'When a visitor is blocked the firewall will send an email to the configured email address' ),
200
- _wpsf__( 'Use with caution - if you get hit by automated bots you may send out too many emails and you could get blocked by your host' )
201
- )
202
- )
203
- );
204
-
205
- $aWhitelistSection = array(
206
- 'section_title' => _wpsf__( 'Whitelists - IPs, Pages, Parameters, and Users that by-pass the Firewall' ),
207
- 'section_options' => array(
208
- array(
209
- 'ips_whitelist',
210
- '',
211
- '',
212
- 'ip_addresses',
213
- _wpsf__( 'Whitelist IP Addresses' ),
214
- _wpsf__( 'Choose IP Addresses that are never subjected to Firewall Rules' ),
215
- sprintf( _wpsf__( 'Take a new line per address. Your IP address is: %s' ), '<span class="code">'.$this->getVisitorIpAddress( false ).'</span>' )
216
- ),
217
- array(
218
- 'page_params_whitelist',
219
- '',
220
- '',
221
- 'comma_separated_lists',
222
- _wpsf__( 'Whitelist Parameters' ),
223
- _wpsf__( 'Detail pages and parameters that are whitelisted (ignored by the firewall)' ),
224
- _wpsf__( 'This should be used with caution and you should only provide parameter names that you must have excluded' )
225
- .' '.sprintf( _wpsf__( '%sHelp%s' ), '[<a href="http://icwp.io/2a" target="_blank">', '</a>]' )
226
- ),
227
- array(
228
- 'whitelist_admins',
229
- '',
230
- 'N',
231
- 'checkbox',
232
- sprintf( _wpsf__( 'Ignore %s' ), _wpsf__( 'Administrators' ) ),
233
- _wpsf__( 'Ignore users logged in as Administrator' ),
234
- _wpsf__( 'Authenticated administrator users will not be processed by the firewall' )
235
- ),
236
- array(
237
- 'ignore_search_engines',
238
- '',
239
- 'N',
240
- 'checkbox',
241
- sprintf( _wpsf__( 'Ignore %s' ), _wpsf__( 'Search Engines' ) ),
242
- _wpsf__( 'Ignore Search Engine Bots' ),
243
- _wpsf__( 'When selected, the firewall will try to recognise search engine spiders/bots and not apply firewall rules to them' )
244
- )
245
- )
246
- );
247
-
248
- $aBlacklistSection = array(
249
- 'section_title' => _wpsf__( 'Choose IP Addresses To Blacklist' ),
250
- 'section_options' => array(
251
- array(
252
- 'ips_blacklist',
253
- '',
254
- '',
255
- 'ip_addresses',
256
- _wpsf__( 'Blacklist IP Addresses' ),
257
- _wpsf__( 'Choose IP Addresses that are always blocked from accessing the site' ),
258
- _wpsf__( 'Take a new line per address. Each IP Address must be valid and will be checked' )
259
- )
260
- )
261
- );
262
- $aMisc = array(
263
- 'section_title' => _wpsf__( 'Logging Options' ),
264
- 'section_options' => array(
265
- array(
266
- 'enable_firewall_log',
267
- '',
268
- 'N',
269
- 'checkbox',
270
- _wpsf__( 'Firewall Logging' ),
271
- _wpsf__( 'Turn on Firewall Log' ),
272
- _wpsf__( 'Will log every visit to the site and how the firewall processes it. Not recommended to leave on unless you want to debug something and check the firewall is working as you expect' )
273
- )
274
- )
275
- );
276
-
277
- $aOptionsDefinitions = array(
278
- $aFirewallBase,
279
- $aBlockSection,
280
- $aWhitelistSection,
281
- $aBlacklistSection,
282
- $aBlockTypesSection,
283
- $aMisc
284
- );
285
- return $aOptionsDefinitions;
286
  }
287
 
288
  /**
289
- * @return bool
 
 
290
  */
291
- public function handleFormSubmit() {
292
- if ( !parent::handleFormSubmit() ) {
293
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  }
295
- $this->loadDataProcessor();
296
 
297
- if ( ICWP_WPSF_DataProcessor::FetchPost( 'clear_log_submit' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
298
  $oLoggingProcessor = $this->getLoggingProcessor();
299
  $oLoggingProcessor->recreateTable();
300
  return true;
301
  }
302
 
303
- $this->addRawIpsToFirewallList( 'ips_whitelist', array( ICWP_WPSF_DataProcessor::FetchGet( 'whiteip' ) ) );
304
- $this->removeRawIpsFromFirewallList( 'ips_whitelist', array( ICWP_WPSF_DataProcessor::FetchGet( 'unwhiteip' ) ) );
305
- $this->addRawIpsToFirewallList( 'ips_blacklist', array( ICWP_WPSF_DataProcessor::FetchGet( 'blackip' ) ) );
306
- $this->removeRawIpsFromFirewallList( 'ips_blacklist', array( ICWP_WPSF_DataProcessor::FetchGet( 'unblackip' ) ) );
307
 
308
  return true;
309
  }
@@ -325,7 +278,8 @@ class ICWP_WPSF_FeatureHandler_Firewall extends ICWP_WPSF_FeatureHandler_Base {
325
  foreach( $inaNewIps as $sAddress ) {
326
  $aNewList[ $sAddress ] = '';
327
  }
328
- $this->setOpt( $insListName, ICWP_WPSF_DataProcessor::Add_New_Raw_Ips( $aIplist, $aNewList ) );
 
329
  }
330
 
331
  public function removeRawIpsFromFirewallList( $insListName, $inaRemoveIps ) {
@@ -337,7 +291,8 @@ class ICWP_WPSF_FeatureHandler_Firewall extends ICWP_WPSF_FeatureHandler_Base {
337
  if ( empty( $aIplist ) || empty( $inaRemoveIps ) ) {
338
  return;
339
  }
340
- $this->setOpt( $insListName, ICWP_WPSF_DataProcessor::Remove_Raw_Ips( $aIplist, $inaRemoveIps ) );
 
341
  }
342
 
343
  }
22
  class ICWP_WPSF_FeatureHandler_Firewall extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
  /**
25
+ * @var ICWP_WPSF_Processor_Firewall
26
  */
27
  protected $oFeatureProcessor;
28
 
33
  }
34
 
35
  /**
36
+ * @return ICWP_WPSF_Processor_Firewall|null
37
  */
38
  protected function loadFeatureProcessor() {
39
  if ( !isset( $this->oFeatureProcessor ) ) {
40
+ require_once( $this->getController()->getSourceDir( sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) ) );
41
+ $this->oFeatureProcessor = new ICWP_WPSF_Processor_Firewall( $this );
42
  }
43
  return $this->oFeatureProcessor;
44
  }
75
  }
76
 
77
  /**
78
+ * @param array $aOptionsParams
79
  * @return array
80
+ * @throws Exception
81
  */
82
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
83
+
84
+ $sSectionSlug = $aOptionsParams['section_slug'];
85
+ switch( $aOptionsParams['section_slug'] ) {
86
+
87
+ case 'section_enable_plugin_feature_wordpress_firewall' :
88
+ $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), $this->getMainFeatureName() );
89
+ break;
90
+
91
+ case 'section_firewall_blocking_options' :
92
+ $sTitle = _wpsf__('Firewall Blocking Options');
93
+ break;
94
+
95
+ case 'section_choose_firewall_block_response' :
96
+ $sTitle = _wpsf__('Choose Firewall Block Response');
97
+ break;
98
+
99
+ case 'section_whitelist' :
100
+ $sTitle = _wpsf__('Whitelists - IPs, Pages, Parameters, and Users that by-pass the Firewall');
101
+ break;
102
+
103
+ case 'section_blacklist' :
104
+ $sTitle = _wpsf__('Choose IP Addresses To Blacklist');
105
+ break;
106
+
107
+ case 'section_firewall_logging' :
108
+ $sTitle = _wpsf__('Firewall Logging Options');
109
+ break;
110
+
111
+ default:
112
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
113
+ }
114
+ $aOptionsParams['section_title'] = $sTitle;
115
+ return $aOptionsParams;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  }
117
 
118
  /**
119
+ * @param array $aOptionsParams
120
+ * @return array
121
+ * @throws Exception
122
  */
123
+ protected function loadStrings_Options( $aOptionsParams ) {
124
+
125
+ $oDp = $this->loadDataProcessor();
126
+ $sKey = $aOptionsParams['key'];
127
+
128
+ switch( $sKey ) {
129
+
130
+ case 'enable_firewall' :
131
+ $sName = sprintf( _wpsf__( 'Enable %s' ), $this->getMainFeatureName() );
132
+ $sSummary = sprintf( _wpsf__( 'Enable (or Disable) The %s Feature' ), $this->getMainFeatureName() );
133
+ $sDescription = sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), $this->getMainFeatureName() );
134
+ break;
135
+
136
+ case 'include_cookie_checks' :
137
+ $sName = _wpsf__( 'Include Cookies' );
138
+ $sSummary = _wpsf__( 'Also Test Cookie Values In Firewall Tests' );
139
+ $sDescription = _wpsf__( 'The firewall tests GET and POST, but with this option checked it will also COOKIE values.' );
140
+ break;
141
+
142
+ case 'block_dir_traversal' :
143
+ $sName = _wpsf__( 'Directory Traversals' );
144
+ $sSummary = _wpsf__( 'Block Directory Traversals' );
145
+ $sDescription = _wpsf__( 'This will block directory traversal paths in in application parameters (e.g. ../, ../../etc/passwd, etc.).' );
146
+ break;
147
+
148
+ case 'block_sql_queries' :
149
+ $sName = _wpsf__( 'SQL Queries' );
150
+ $sSummary = _wpsf__( 'Block SQL Queries' );
151
+ $sDescription = _wpsf__( 'This will block sql in application parameters (e.g. union select, concat(, /**/, etc.).' );
152
+ break;
153
+
154
+ case 'block_wordpress_terms' :
155
+ $sName = _wpsf__( 'WordPress Terms' );
156
+ $sSummary = _wpsf__( 'Block WordPress Specific Terms' );
157
+ $sDescription = _wpsf__( 'This will block WordPress specific terms in application parameters (wp_, user_login, etc.).' );
158
+ break;
159
+
160
+ case 'block_field_truncation' :
161
+ $sName = _wpsf__( 'Field Truncation' );
162
+ $sSummary = _wpsf__( 'Block Field Truncation Attacks' );
163
+ $sDescription = _wpsf__( 'This will block field truncation attacks in application parameters.' );
164
+ break;
165
+
166
+ case 'block_php_code' :
167
+ $sName = _wpsf__( 'PHP Code' );
168
+ $sSummary = sprintf( _wpsf__( 'Block %s' ), _wpsf__( 'PHP Code Includes' ) );
169
+ $sDescription = _wpsf__( 'This will block any data that appears to try and include PHP files.' )
170
+ .'<br />'. _wpsf__( 'Will probably block saving within the Plugin/Theme file editors.' );
171
+ break;
172
+
173
+ case 'block_exe_file_uploads' :
174
+ $sName = _wpsf__( 'Exe File Uploads' );
175
+ $sSummary = _wpsf__( 'Block Executable File Uploads' );
176
+ $sDescription = _wpsf__( 'This will block executable file uploads (.php, .exe, etc.).' );
177
+ break;
178
+
179
+ case 'block_leading_schema' :
180
+ $sName = _wpsf__( 'Leading Schemas' );
181
+ $sSummary = _wpsf__( 'Block Leading Schemas (HTTPS / HTTP)' );
182
+ $sDescription = _wpsf__( 'This will block leading schemas http:// and https:// in application parameters (off by default; may cause problems with other plugins).' );
183
+ break;
184
+
185
+ case 'block_response' :
186
+ $sName = _wpsf__( 'Block Response' );
187
+ $sSummary = _wpsf__( 'Choose how the firewall responds when it blocks a request' );
188
+ $sDescription = _wpsf__( 'We recommend dying with a message so you know what might have occurred when the firewall blocks you' );
189
+ break;
190
+
191
+ case 'block_send_email' :
192
+ $sName = _wpsf__( 'Send Email Report' );
193
+ $sSummary = _wpsf__( 'When a visitor is blocked the firewall will send an email to the configured email address' );
194
+ $sDescription = _wpsf__( 'Use with caution - if you get hit by automated bots you may send out too many emails and you could get blocked by your host' );
195
+ break;
196
+
197
+ case 'ips_whitelist' :
198
+ $sName = _wpsf__( 'Whitelist IP Addresses' );
199
+ $sSummary = _wpsf__( 'Choose IP Addresses that are never subjected to Firewall Rules' );
200
+ $sDescription = _wpsf__( 'Take a new line per address.' )
201
+ .'<br />'.sprintf( _wpsf__( 'Your IP address is: %s' ), '<span class="code">'.( $oDp->GetVisitorIpAddress( false ) ).'</span>' );
202
+ break;
203
+
204
+ case 'page_params_whitelist' :
205
+ $sName = _wpsf__( 'Whitelist Parameters' );
206
+ $sSummary = _wpsf__( 'Detail pages and parameters that are whitelisted (ignored by the firewall)' );
207
+ $sDescription = _wpsf__( 'This should be used with caution and you should only provide parameter names that you must have excluded' );
208
+ break;
209
+
210
+ case 'whitelist_admins' :
211
+ $sName = sprintf( _wpsf__( 'Ignore %s' ), _wpsf__( 'Administrators' ) );
212
+ $sSummary = sprintf( _wpsf__( 'Ignore %s' ), _wpsf__( 'Administrators' ) );
213
+ $sDescription = _wpsf__( 'Authenticated administrator users will not be processed by the firewall rules.' );
214
+ break;
215
+
216
+ case 'ignore_search_engines' :
217
+ $sName = sprintf( _wpsf__( 'Ignore %s' ), _wpsf__( 'Search Engines' ) );
218
+ $sSummary = _wpsf__( 'Ignore Search Engine Bot Traffic' );
219
+ $sDescription = _wpsf__( 'The firewall will try to recognise search engine spiders/bots and not apply firewall rules to them.' );
220
+ break;
221
+
222
+ case 'ips_blacklist' :
223
+ $sName = _wpsf__( 'Blacklist IP Addresses' );
224
+ $sSummary = _wpsf__( 'Choose IP Addresses that are always blocked from accessing the site' );
225
+ $sDescription = _wpsf__( 'Take a new line per address. Each IP Address must be valid and will be checked.' );
226
+ break;
227
+
228
+ case 'enable_firewall_log' :
229
+ $sName = _wpsf__( 'Firewall Logging' );
230
+ $sSummary = _wpsf__( 'Turn on Firewall Log' );
231
+ $sDescription = _wpsf__( 'Will log every visit to the site and how the firewall processes it. Not recommended to leave on unless you want to debug something and check the firewall is working as you expect' );
232
+ break;
233
+
234
+ default:
235
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
236
  }
 
237
 
238
+ $aOptionsParams['name'] = $sName;
239
+ $aOptionsParams['summary'] = $sSummary;
240
+ $aOptionsParams['description'] = $sDescription;
241
+ return $aOptionsParams;
242
+ }
243
+
244
+ /**
245
+ * @return bool
246
+ */
247
+ protected function doExtraSubmitProcessing() {
248
+ $oDp = $this->loadDataProcessor();
249
+
250
+ if ( $oDp->FetchPost( 'clear_log_submit' ) ) {
251
  $oLoggingProcessor = $this->getLoggingProcessor();
252
  $oLoggingProcessor->recreateTable();
253
  return true;
254
  }
255
 
256
+ $this->addRawIpsToFirewallList( 'ips_whitelist', array( $oDp->FetchGet( 'whiteip' ) ) );
257
+ $this->removeRawIpsFromFirewallList( 'ips_whitelist', array( $oDp->FetchGet( 'unwhiteip' ) ) );
258
+ $this->addRawIpsToFirewallList( 'ips_blacklist', array( $oDp->FetchGet( 'blackip' ) ) );
259
+ $this->removeRawIpsFromFirewallList( 'ips_blacklist', array( $oDp->FetchGet( 'unblackip' ) ) );
260
 
261
  return true;
262
  }
278
  foreach( $inaNewIps as $sAddress ) {
279
  $aNewList[ $sAddress ] = '';
280
  }
281
+ $oDp = $this->loadDataProcessor();
282
+ $this->setOpt( $insListName, $oDp->Add_New_Raw_Ips( $aIplist, $aNewList ) );
283
  }
284
 
285
  public function removeRawIpsFromFirewallList( $insListName, $inaRemoveIps ) {
291
  if ( empty( $aIplist ) || empty( $inaRemoveIps ) ) {
292
  return;
293
  }
294
+ $oDp = $this->loadDataProcessor();
295
+ $this->setOpt( $insListName, $oDp->Remove_Raw_Ips( $aIplist, $inaRemoveIps ) );
296
  }
297
 
298
  }
src/icwp-optionshandler-lockdown.php CHANGED
@@ -22,7 +22,7 @@ if ( !class_exists('ICWP_WPSF_FeatureHandler_Lockdown') ):
22
  class ICWP_WPSF_FeatureHandler_Lockdown extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
  /**
25
- * @var ICWP_WPSF_LockdownProcessor
26
  */
27
  protected $oFeatureProcessor;
28
 
@@ -36,12 +36,12 @@ class ICWP_WPSF_FeatureHandler_Lockdown extends ICWP_WPSF_FeatureHandler_Base {
36
  }
37
 
38
  /**
39
- * @return ICWP_WPSF_LockdownProcessor|null
40
  */
41
  protected function loadFeatureProcessor() {
42
  if ( !isset( $this->oFeatureProcessor ) ) {
43
- require_once( dirname(__FILE__).'/icwp-processor-lockdown.php' );
44
- $this->oFeatureProcessor = new ICWP_WPSF_LockdownProcessor( $this );
45
  }
46
  return $this->oFeatureProcessor;
47
  }
@@ -62,115 +62,94 @@ class ICWP_WPSF_FeatureHandler_Lockdown extends ICWP_WPSF_FeatureHandler_Base {
62
  }
63
 
64
  /**
 
65
  * @return array
 
66
  */
67
- protected function getOptionsDefinitions() {
68
-
69
- $aBase = array(
70
- 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('WordPress Lockdown') ),
71
- 'section_options' => array(
72
- array(
73
- 'enable_lockdown',
74
- '',
75
- 'N',
76
- 'checkbox',
77
- _wpsf__( 'Enable Lockdown' ),
78
- _wpsf__( 'Enable (or Disable) The Lockdown Feature' ),
79
- sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('WordPress Lockdown') ),
80
- '<a href="http://icwp.io/4r" target="_blank">'._wpsf__( 'more info' ).'</a>'
81
- )
82
- )
83
- );
84
- $aAccess = array(
85
- 'section_title' => _wpsf__( 'Access Options' ),
86
- 'section_options' => array(
87
- array(
88
- 'disable_file_editing',
89
- '',
90
- 'N',
91
- 'checkbox',
92
- _wpsf__( 'Disable File Editing' ),
93
- _wpsf__( 'Disable Ability To Edit Files' ),
94
- _wpsf__( 'Removes the option to directly edit any files from within the WordPress admin area.' )
95
- .'<br />'._wpsf__( 'Equivalent to setting DISALLOW_FILE_EDIT to TRUE.' ),
96
- '<a href="http://icwp.io/4q" target="_blank">'._wpsf__( 'more info' ).'</a>'
97
- ),
98
- array(
99
- 'force_ssl_login',
100
- '',
101
- 'N',
102
- 'checkbox',
103
- _wpsf__( 'Force SSL Login' ),
104
- _wpsf__( 'Forces Login Form To Be Submitted Over SSL' ),
105
- _wpsf__( 'Please only enable this option if you have a valid SSL certificate installed.' )
106
- .'<br />'._wpsf__( 'Equivalent to setting FORCE_SSL_LOGIN to TRUE.' ),
107
- '<a href="http://icwp.io/4s" target="_blank">'._wpsf__( 'more info' ).'</a>'
108
- ),
109
- array(
110
- 'force_ssl_admin',
111
- '',
112
- 'N',
113
- 'checkbox',
114
- _wpsf__( 'Force SSL Admin' ),
115
- _wpsf__( 'Forces WordPress Admin Dashboard To Be Delivered Over SSL' ),
116
- _wpsf__( 'Please only enable this option if you have a valid SSL certificate installed.' )
117
- .'<br />'._wpsf__( 'Equivalent to setting FORCE_SSL_ADMIN to TRUE.' ),
118
- '<a href="http://icwp.io/4t" target="_blank">'._wpsf__( 'more info' ).'</a>'
119
- )
120
- )
121
- );
122
- $aObscurity = array(
123
- 'section_title' => _wpsf__( 'WordPress Obscurity Options' ),
124
- 'section_options' => array(
125
- array(
126
- 'mask_wordpress_version',
127
- '',
128
- '',
129
- 'text',
130
- _wpsf__( 'Mask WordPress Version' ),
131
- _wpsf__( 'Prevents Public Display Of Your WordPress Version' ),
132
- _wpsf__( 'Enter how you would like your WordPress version displayed publicly. Leave blank to disable this feature.' )
133
- .'<br />'._wpsf__( 'Warning: This may interfere with WordPress plugins that rely on the $wp_version variable.' ),
134
- '<a href="http://icwp.io/43" target="_blank">'._wpsf__( 'more info' ).'</a>'
135
- ),
136
- array(
137
- 'hide_wordpress_generator_tag',
138
- '',
139
- 'N',
140
- 'checkbox',
141
- _wpsf__( 'WP Generator Tag' ),
142
- _wpsf__( 'Remove WP Generator Meta Tag' ),
143
- _wpsf__( 'Remove a meta tag from your WordPress pages that publicly displays that your site is WordPress and its current version.' )
144
- )
145
- )
146
- );
147
-
148
- $aOptionsDefinitions = array(
149
- $aBase,
150
- $aAccess,
151
- $aObscurity
152
- );
153
- return $aOptionsDefinitions;
154
-
155
- if ( false && $this->getCanDoAuthSalts() ) {
156
- $this->aOptions[] = array(
157
- 'section_title' => _wpsf__( 'Security Actions' ),
158
- 'section_options' => array(
159
- array(
160
- 'action_reset_auth_salts',
161
- '',
162
- 'N',
163
- 'checkbox',
164
- _wpsf__( 'Reset Auth Keys/Salts' ),
165
- _wpsf__( 'Reset WordPress Authentication Keys and Salts' ),
166
- _wpsf__( 'Selecting this will reset the WordPress Authentication Keys and Salts in your wp-config.php file.' )
167
- .'<br /><strong>'._wpsf__( 'Note: This will log you and all other users out of their current session.' ).'</strong>'
168
- )
169
- )
170
- );
171
  }
 
 
 
 
 
172
  }
173
-
174
  protected function getCanDoAuthSalts() {
175
  $oWpFs = $this->loadFileSystemProcessor();
176
 
@@ -190,7 +169,6 @@ class ICWP_WPSF_FeatureHandler_Lockdown extends ICWP_WPSF_FeatureHandler_Base {
190
  $mResult = $oWpFs->getCanReadWriteFile( $sWpConfigPath );
191
  return !empty( $mResult );
192
  }
193
-
194
  }
195
 
196
  endif;
22
  class ICWP_WPSF_FeatureHandler_Lockdown extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
  /**
25
+ * @var ICWP_WPSF_Processor_Lockdown
26
  */
27
  protected $oFeatureProcessor;
28
 
36
  }
37
 
38
  /**
39
+ * @return ICWP_WPSF_Processor_Lockdown|null
40
  */
41
  protected function loadFeatureProcessor() {
42
  if ( !isset( $this->oFeatureProcessor ) ) {
43
+ require_once( $this->getController()->getSourceDir( sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) ) );
44
+ $this->oFeatureProcessor = new ICWP_WPSF_Processor_Lockdown( $this );
45
  }
46
  return $this->oFeatureProcessor;
47
  }
62
  }
63
 
64
  /**
65
+ * @param array $aOptionsParams
66
  * @return array
67
+ * @throws Exception
68
  */
69
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
70
+
71
+ $sSectionSlug = $aOptionsParams['section_slug'];
72
+ switch( $aOptionsParams['section_slug'] ) {
73
+
74
+ case 'section_enable_plugin_feature_wordpress_lockdown' :
75
+ $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), $this->getMainFeatureName() );
76
+ break;
77
+
78
+ case 'section_permission_access_options' :
79
+ $sTitle = _wpsf__('Permissions and Access Options');
80
+ break;
81
+
82
+ case 'section_wordpress_obscurity_options' :
83
+ $sTitle = _wpsf__('WordPress Obscurity Options');
84
+ break;
85
+
86
+ default:
87
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
88
+ }
89
+ $aOptionsParams['section_title'] = $sTitle;
90
+ return $aOptionsParams;
91
+ }
92
+
93
+ /**
94
+ * @param array $aOptionsParams
95
+ * @return array
96
+ * @throws Exception
97
+ */
98
+ protected function loadStrings_Options( $aOptionsParams ) {
99
+
100
+ $sKey = $aOptionsParams['key'];
101
+ switch( $sKey ) {
102
+
103
+ case 'enable_lockdown' :
104
+ $sName = sprintf( _wpsf__( 'Enable %s' ), $this->getMainFeatureName() );
105
+ $sSummary = sprintf( _wpsf__( 'Enable (or Disable) The %s Feature' ), $this->getMainFeatureName() );
106
+ $sDescription = sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), $this->getMainFeatureName() );
107
+ break;
108
+
109
+ case 'disable_file_editing' :
110
+ $sName = _wpsf__( 'Disable File Editing' );
111
+ $sSummary = _wpsf__( 'Disable Ability To Edit Files From Within WordPress' );
112
+ $sDescription = _wpsf__( 'Removes the option to directly edit any files from within the WordPress admin area.' )
113
+ .'<br />'._wpsf__( 'Equivalent to setting "DISALLOW_FILE_EDIT" to TRUE.' );
114
+ break;
115
+
116
+ case 'force_ssl_login' :
117
+ $sName = _wpsf__( 'Force SSL Login' );
118
+ $sSummary = _wpsf__( 'Forces Login Form To Be Submitted Over SSL' );
119
+ $sDescription = _wpsf__( 'Please only enable this option if you have a valid SSL certificate installed.' )
120
+ .'<br />'._wpsf__( 'Equivalent to setting FORCE_SSL_LOGIN to TRUE.' );
121
+ break;
122
+
123
+ case 'force_ssl_admin' :
124
+ $sName = _wpsf__( 'Force SSL Admin' );
125
+ $sSummary = _wpsf__( 'Forces WordPress Admin Dashboard To Be Delivered Over SSL' );
126
+ $sDescription = _wpsf__( 'Please only enable this option if you have a valid SSL certificate installed.' )
127
+ .'<br />'._wpsf__( 'Equivalent to setting "FORCE_SSL_ADMIN" to TRUE.' );
128
+ break;
129
+
130
+ case 'mask_wordpress_version' :
131
+ $sName = _wpsf__( 'Mask WordPress Version' );
132
+ $sSummary = _wpsf__( 'Prevents Public Display Of Your WordPress Version' );
133
+ $sDescription = _wpsf__( 'Enter how you would like your WordPress version displayed publicly. Leave blank to disable this feature.' )
134
+ .'<br />'._wpsf__( 'Warning: This may interfere with WordPress plugins that rely on the $wp_version variable.' );
135
+ break;
136
+
137
+ case 'hide_wordpress_generator_tag' :
138
+ $sName = _wpsf__( 'WP Generator Tag' );
139
+ $sSummary = _wpsf__( 'Remove WP Generator Meta Tag' );
140
+ $sDescription = _wpsf__( 'Remove a meta tag from your WordPress pages that publicly displays that your site is WordPress and its current version.' );
141
+ break;
142
+
143
+ default:
144
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  }
146
+
147
+ $aOptionsParams['name'] = $sName;
148
+ $aOptionsParams['summary'] = $sSummary;
149
+ $aOptionsParams['description'] = $sDescription;
150
+ return $aOptionsParams;
151
  }
152
+
153
  protected function getCanDoAuthSalts() {
154
  $oWpFs = $this->loadFileSystemProcessor();
155
 
169
  $mResult = $oWpFs->getCanReadWriteFile( $sWpConfigPath );
170
  return !empty( $mResult );
171
  }
 
172
  }
173
 
174
  endif;
src/icwp-optionshandler-logging.php CHANGED
@@ -22,7 +22,7 @@ if ( !class_exists('ICWP_WPSF_FeatureHandler_Logging') ):
22
  class ICWP_WPSF_FeatureHandler_Logging extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
  /**
25
- * @var ICWP_WPSF_LoggingProcessor
26
  */
27
  protected $oFeatureProcessor;
28
 
@@ -32,50 +32,74 @@ class ICWP_WPSF_FeatureHandler_Logging extends ICWP_WPSF_FeatureHandler_Base {
32
  public function __construct( $oPluginVo ) {
33
  $this->sFeatureName = _wpsf__('Logging');
34
  $this->sFeatureSlug = 'logging';
35
- $this->fShowFeatureMenuItem = false;
36
  parent::__construct( $oPluginVo );
37
  }
38
 
39
  /**
40
- * @return ICWP_WPSF_LoggingProcessor|null
41
  */
42
  protected function loadFeatureProcessor() {
 
43
  if ( !isset( $this->oFeatureProcessor ) ) {
44
- require_once( dirname(__FILE__).'/icwp-processor-logging.php' );
45
- $this->oFeatureProcessor = new ICWP_WPSF_LoggingProcessor( $this );
46
  }
47
  return $this->oFeatureProcessor;
48
  }
49
 
50
  /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  * @return array
 
52
  */
53
- protected function getOptionsDefinitions() {
54
- $aBase = array(
55
- 'section_title' => _wpsf__( 'Enable Logging' ),
56
- 'section_options' => array(
57
- array(
58
- 'enable_logging',
59
- '',
60
- 'Y',
61
- 'checkbox',
62
- _wpsf__( 'Enable Logging' ),
63
- _wpsf__( 'Enable (or Disable) The Plugin Logging Feature.' ),
64
- _wpsf__( 'Regardless of any other settings, this option will turn off the Logging system, or enable your chosen Logging options.' )
65
- )
66
- )
67
- );
68
-
69
- $aOptionsDefinitions = array(
70
- $aBase
71
- );
72
- return $aOptionsDefinitions;
73
  }
74
 
75
  /**
76
- * This is the point where you would want to do any options verification
77
  */
78
- protected function doPrePluginOptionsSave() { }
 
 
79
  }
80
 
81
  endif;
22
  class ICWP_WPSF_FeatureHandler_Logging extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
  /**
25
+ * @var ICWP_WPSF_Processor_Logging
26
  */
27
  protected $oFeatureProcessor;
28
 
32
  public function __construct( $oPluginVo ) {
33
  $this->sFeatureName = _wpsf__('Logging');
34
  $this->sFeatureSlug = 'logging';
 
35
  parent::__construct( $oPluginVo );
36
  }
37
 
38
  /**
39
+ * @return ICWP_WPSF_Processor_Logging|null
40
  */
41
  protected function loadFeatureProcessor() {
42
+
43
  if ( !isset( $this->oFeatureProcessor ) ) {
44
+ require_once( $this->getController()->getSourceDir( sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) ) );
45
+ $this->oFeatureProcessor = new ICWP_WPSF_Processor_Logging( $this );
46
  }
47
  return $this->oFeatureProcessor;
48
  }
49
 
50
  /**
51
+ * @param array $aOptionsParams
52
+ * @return array
53
+ * @throws Exception
54
+ */
55
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
56
+
57
+ $sSectionSlug = $aOptionsParams['section_slug'];
58
+ switch( $aOptionsParams['section_slug'] ) {
59
+
60
+ case 'section_logging_options' :
61
+ $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('Logging') );
62
+ break;
63
+
64
+ default:
65
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
66
+ }
67
+ $aOptionsParams['section_title'] = $sTitle;
68
+ return $aOptionsParams;
69
+ }
70
+
71
+ /**
72
+ * @param array $aOptionsParams
73
  * @return array
74
+ * @throws Exception
75
  */
76
+ protected function loadStrings_Options( $aOptionsParams ) {
77
+
78
+ $sKey = $aOptionsParams['key'];
79
+ switch( $sKey ) {
80
+
81
+ case 'enable_logging' :
82
+ $sName = sprintf( _wpsf__( 'Enable %s' ), $this->getMainFeatureName() );
83
+ $sSummary = sprintf( _wpsf__( 'Enable (or Disable) The %s Feature' ), $this->getMainFeatureName() );
84
+ $sDescription = sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), $this->getMainFeatureName() );
85
+ break;
86
+
87
+ default:
88
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
89
+ }
90
+
91
+ $aOptionsParams['name'] = $sName;
92
+ $aOptionsParams['summary'] = $sSummary;
93
+ $aOptionsParams['description'] = $sDescription;
94
+ return $aOptionsParams;
 
95
  }
96
 
97
  /**
98
+ * @return string
99
  */
100
+ public function getGeneralLoggingTableName() {
101
+ return $this->doPluginPrefix( $this->getOpt( 'general_logging_table_name' ), '_' );
102
+ }
103
  }
104
 
105
  endif;
src/icwp-optionshandler-login_protect.php CHANGED
@@ -20,9 +20,9 @@ require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
20
  if ( !class_exists('ICWP_WPSF_FeatureHandler_LoginProtect') ):
21
 
22
  class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Base {
23
-
24
  /**
25
- * @var ICWP_WPSF_LoginProtectProcessor
26
  */
27
  protected $oFeatureProcessor;
28
 
@@ -33,17 +33,22 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
33
  }
34
 
35
  /**
36
- * @return ICWP_WPSF_LoginProtectProcessor|null
37
  */
38
  protected function loadFeatureProcessor() {
39
  if ( !isset( $this->oFeatureProcessor ) ) {
40
- require_once( dirname(__FILE__).'/icwp-processor-loginprotect.php' );
41
- $this->oFeatureProcessor = new ICWP_WPSF_LoginProtectProcessor( $this );
42
  }
43
  return $this->oFeatureProcessor;
44
  }
45
 
46
  public function doPrePluginOptionsSave() {
 
 
 
 
 
47
  $aIpWhitelist = $this->getOpt( 'ips_whitelist' );
48
  if ( $aIpWhitelist === false ) {
49
  $aIpWhitelist = '';
@@ -56,237 +61,181 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
56
  $this->setOpt( 'two_factor_auth_user_roles', $this->getTwoFactorUserAuthRoles( true ) );
57
  }
58
 
59
- $this->setKeys(); // ensures they have values
 
 
60
  }
61
 
62
  /**
 
63
  * @return array
 
64
  */
65
- protected function getOptionsDefinitions() {
66
- $aOptionsBase = array(
67
- 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('Login Protection') ),
68
- 'section_options' => array(
69
- array(
70
- 'enable_login_protect',
71
- '',
72
- 'N',
73
- 'checkbox',
74
- _wpsf__( 'Enable Login Protect' ),
75
- _wpsf__( 'Enable (or Disable) The Login Protection Feature' ),
76
- sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('Login Protection') ),
77
- '<a href="http://icwp.io/51" target="_blank">'._wpsf__( 'more info' ).'</a>'
78
- .' | <a href="http://icwp.io/wpsf03" target="_blank">'._wpsf__( 'blog' ).'</a>'
79
- )
80
- ),
81
- );
82
- $aWhitelist = array(
83
- 'section_title' => _wpsf__( 'Whitelist IPs that by-pass Login Protect' ),
84
- 'section_options' => array(
85
- array(
86
- 'ips_whitelist',
87
- '',
88
- '',
89
- 'ip_addresses',
90
- _wpsf__( 'Whitelist IP Addresses' ),
91
- _wpsf__( 'Specify IP Addresses that by-pass all Login Protect rules' ),
92
- sprintf( _wpsf__( 'Take a new line per address. Your IP address is: %s' ), '<span class="code">'.$this->getVisitorIpAddress( false ).'</span>' ),
93
- '<a href="http://icwp.io/52" target="_blank">'._wpsf__( 'more info' ).'</a>'
94
- )
95
- )
96
- );
97
 
98
- $aTwoFactorAuth = array(
99
- 'section_title' => _wpsf__( 'Two-Factor Authentication Protection Options' ),
100
- 'section_options' => array(
101
- array(
102
- 'two_factor_auth_user_roles',
103
- '',
104
- $this->getTwoFactorUserAuthRoles( true ), // default is Contributors, Authors, Editors and Administrators
105
- $this->getTwoFactorUserAuthRoles(),
106
- _wpsf__( 'Two-Factor Auth User Roles' ),
107
- _wpsf__( 'All User Roles Subject To Two-Factor Authentication' ),
108
- _wpsf__( 'Select which types of users/roles will be subject to two-factor login authentication.' ),
109
- '<a href="http://icwp.io/4v" target="_blank">'._wpsf__( 'more info' ).'</a>'
110
- ),
111
- array(
112
- 'enable_two_factor_auth_by_ip',
113
- '',
114
- 'N',
115
- 'checkbox',
116
- sprintf( _wpsf__( 'Two-Factor Authentication (%s)' ), _wpsf__('IP') ),
117
- sprintf( _wpsf__( 'Two-Factor Login Authentication By %s' ), _wpsf__('IP Address') ),
118
- _wpsf__( 'All users will be required to authenticate their logins by email-based two-factor authentication when logging in from a new IP address' ),
119
- '<a href="http://icwp.io/3s" target="_blank">'._wpsf__( 'more info' ).'</a>'
120
- ),
121
- array(
122
- 'enable_two_factor_auth_by_cookie',
123
- '',
124
- 'N',
125
- 'checkbox',
126
- sprintf( _wpsf__( 'Two-Factor Authentication (%s)' ), _wpsf__('Cookie') ),
127
- sprintf( _wpsf__( 'Two-Factor Login Authentication By %s' ), _wpsf__('Cookie') ),
128
- _wpsf__( 'This will restrict all user login sessions to a single browser. Use this if your users have dynamic IP addresses.' ),
129
- '<a href="http://icwp.io/3t" target="_blank">'._wpsf__( 'more info' ).'</a>'
130
- ),
131
- array(
132
- 'enable_two_factor_bypass_on_email_fail',
133
- '',
134
- 'N',
135
- 'checkbox',
136
- _wpsf__( 'By-Pass On Failure' ),
137
- _wpsf__( 'If Sending Verification Email Sending Fails, Two-Factor Login Authentication Is Ignored' ),
138
- _wpsf__( 'If you enable two-factor authentication and sending the email with the verification link fails, turning this setting on will by-pass the verification step. Use with caution' )
139
- )
140
- )
141
- );
142
- $aLoginProtect = array(
143
- 'section_title' => _wpsf__( 'Login Protection Options' ),
144
- 'section_options' => array(
145
- array(
146
- 'login_limit_interval',
147
- '',
148
- '10',
149
- 'integer',
150
- _wpsf__('Login Cooldown Interval'),
151
- _wpsf__('Limit login attempts to every X seconds'),
152
- _wpsf__('WordPress will process only ONE login attempt for every number of seconds specified. Zero (0) turns this off. Suggested: 5'),
153
- '<a href="http://icwp.io/3q" target="_blank">'._wpsf__( 'more info' ).'</a>'
154
- ),
155
- array(
156
- 'enable_login_gasp_check',
157
- '',
158
- 'Y',
159
- 'checkbox',
160
- _wpsf__( 'G.A.S.P Protection' ),
161
- _wpsf__( 'Use G.A.S.P. Protection To Prevent Login Attempts By Bots' ),
162
- _wpsf__( 'Adds a dynamically (Javascript) generated checkbox to the login form that prevents bots using automated login techniques. Recommended: ON' ),
163
- '<a href="http://icwp.io/3r" target="_blank">'._wpsf__( 'more info' ).'</a>'
164
- ),
165
- array(
166
- 'enable_prevent_remote_post',
167
- '',
168
- 'Y',
169
- 'checkbox',
170
- _wpsf__( 'Prevent Remote Login' ),
171
- _wpsf__( 'Prevents Remote Login Attempts From Other Locations' ),
172
- _wpsf__( 'Prevents any login attempts that do not originate from your website. This prevent bots from attempting to login remotely. Recommended: ON' ),
173
- '<a href="http://icwp.io/4n" target="_blank">'._wpsf__( 'more info' ).'</a>'
174
- )
175
- )
176
- );
177
 
178
- $aYubikeyProtect = array(
179
- 'section_title' => _wpsf__( 'Yubikey Authentication' ),
180
- 'section_options' => array(
181
- array(
182
- 'enable_yubikey',
183
- '',
184
- 'N',
185
- 'checkbox',
186
- _wpsf__('Enable Yubikey Authentication'),
187
- _wpsf__('Turn On / Off Yubikey Authentication On This Site'),
188
- _wpsf__('Combined with your Yubikey API Key (below) this will form the basis of your Yubikey Authentication'),
189
- '<a href="http://icwp.io/4f" target="_blank">'._wpsf__( 'more info' ).'</a>'
190
- ),
191
- array(
192
- 'yubikey_app_id',
193
- '',
194
- '',
195
- 'text',
196
- _wpsf__('Yubikey App ID'),
197
- _wpsf__('Your Unique Yubikey App ID'),
198
- _wpsf__('Combined with your Yubikey API Key (below) this will form the basis of your Yubikey Authentication')
199
- . _wpsf__( 'Please review the [more info] link on how to get your own Yubikey App ID and API Key.' ),
200
- '<a href="http://icwp.io/4g" target="_blank">'._wpsf__( 'more info' ).'</a>'
201
- ),
202
- array(
203
- 'yubikey_api_key',
204
- '',
205
- '',
206
- 'text',
207
- _wpsf__( 'Yubikey API Key' ),
208
- _wpsf__( 'Your Unique Yubikey App API Key' ),
209
- _wpsf__( 'Combined with your Yubikey App ID (above) this will form the basis of your Yubikey Authentication.' )
210
- . _wpsf__( 'Please review the [more info] link on how to get your own Yubikey App ID and API Key.' ),
211
- '<a href="http://icwp.io/4g" target="_blank">'._wpsf__( 'more info' ).'</a>'
212
- ),
213
- array(
214
- 'yubikey_unique_keys',
215
- '',
216
- '',
217
- 'yubikey_unique_keys',
218
- _wpsf__( 'Yubikey Unique Keys' ),
219
- _wpsf__( 'Permitted Username - Yubikey Pairs For This Site' ),
220
- '<strong>'. sprintf( _wpsf__( 'Format: %s' ), 'Username,Yubikey').'</strong>'
221
- .'<br />- '. _wpsf__( 'Provide Username<->Yubikey Pairs that are usable on this site.')
222
- .'<br />- '. _wpsf__( 'If a Username if not assigned a Yubikey, Yubikey Authentication is OFF for that user.')
223
- .'<br />- '. _wpsf__( 'Each [Username,Key] pair should be separated by a new line: you only need to provide the first 12 characters of the yubikey.' ),
224
- '<a href="http://icwp.io/4h" target="_blank">'._wpsf__( 'more info' ).'</a>'
225
- ),
226
- /*
227
- array(
228
- 'enable_yubikey_only',
229
- '',
230
- 'N',
231
- 'checkbox',
232
- _wpsf__('Enable Yubikey Only'),
233
- _wpsf__('Turn On / Off Yubikey Only Authentication'),
234
- _wpsf__('Yubikey Only Authentication is where you can login into your WordPress site with just a Yubikey OTP.')
235
- .'<br />- '. _wpsf__("You don't need to enter a username or a password, just a valid Yubikey OTP.")
236
- .'<br />- '. _wpsf__("Check your list of Yubikeys as only 1 WordPress username may be assigned to a given Yubikey ID (but you may have multiple Yubikeys for a given username)."),
237
- sprintf( _wpsf__( '%smore info%s' ), '<a href="http://icwp.io/4f" target="_blank">', '</a>' )
238
- ),*/
239
- )
240
- );
241
-
242
- $aLoggingSection = array(
243
- 'section_title' => _wpsf__( 'Logging Options' ),
244
- 'section_options' => array(
245
- array(
246
- 'enable_login_protect_log',
247
- '',
248
- 'N',
249
- 'checkbox',
250
- _wpsf__( 'Login Protect Logging' ),
251
- _wpsf__( 'Turn on a detailed Login Protect Log' ),
252
- _wpsf__( 'Will log every event related to login protection and how it is processed. Not recommended to leave on unless you want to debug something and check the login protection is working as you expect.' )
253
- )
254
- )
255
- );
256
 
257
- $aOptionsDefinitions = array(
258
- $aOptionsBase,
259
- $aWhitelist,
260
- $aLoginProtect,
261
- $aTwoFactorAuth,
262
- $aYubikeyProtect,
263
- $aLoggingSection
264
- );
265
- return $aOptionsDefinitions;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  }
267
 
268
  /**
 
269
  * @return array
 
270
  */
271
- protected function getNonUiOptions() {
272
- $aNonUiOptions = array(
273
- 'gasp_key',
274
- 'two_factor_secret_key'
275
- );
276
- return $aNonUiOptions;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  }
278
 
279
  /**
280
  * @return bool|void
281
  */
282
- public function handleFormSubmit() {
283
- $fSuccess = parent::handleFormSubmit();
284
- if ( !$fSuccess ) {
285
- return;
286
- }
287
-
288
  // When they've clicked to terminate all logged in authenticated users.
289
- if ( ICWP_WPSF_DataProcessor::FetchPost( 'terminate-all-logins' ) ) {
 
290
  $oProc = $this->getProcessor();
291
  $oProc->doTerminateAllVerifiedLogins();
292
  return;
@@ -309,11 +258,20 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
309
  if ( $fAsDefaults ) {
310
  unset($aTwoAuthRoles['type']);
311
  unset($aTwoAuthRoles[0]);
312
- return array_keys($aTwoAuthRoles);
313
  }
314
  return $aTwoAuthRoles;
315
  }
316
 
 
 
 
 
 
 
 
 
 
317
  /**
318
  * @return string
319
  */
@@ -334,6 +292,20 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
334
  return $sKey;
335
  }
336
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  /**
338
  * @return string
339
  */
@@ -345,6 +317,28 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
345
  }
346
  return $sKey;
347
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  }
349
 
350
  endif;
20
  if ( !class_exists('ICWP_WPSF_FeatureHandler_LoginProtect') ):
21
 
22
  class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Base {
23
+
24
  /**
25
+ * @var ICWP_WPSF_Processor_LoginProtect
26
  */
27
  protected $oFeatureProcessor;
28
 
33
  }
34
 
35
  /**
36
+ * @return ICWP_WPSF_Processor_LoginProtect|null
37
  */
38
  protected function loadFeatureProcessor() {
39
  if ( !isset( $this->oFeatureProcessor ) ) {
40
+ require_once( $this->getController()->getSourceDir( sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) ) );
41
+ $this->oFeatureProcessor = new ICWP_WPSF_Processor_LoginProtect( $this );
42
  }
43
  return $this->oFeatureProcessor;
44
  }
45
 
46
  public function doPrePluginOptionsSave() {
47
+
48
+ if ( $this->getOpt( 'login_limit_interval' ) < 0 ) {
49
+ $this->getOptionsVo()->resetOptToDefault( 'login_limit_interval' );
50
+ }
51
+
52
  $aIpWhitelist = $this->getOpt( 'ips_whitelist' );
53
  if ( $aIpWhitelist === false ) {
54
  $aIpWhitelist = '';
61
  $this->setOpt( 'two_factor_auth_user_roles', $this->getTwoFactorUserAuthRoles( true ) );
62
  }
63
 
64
+ // ensures they have values
65
+ $this->setKeys();
66
+ $this->getLastLoginTimeFilePath();
67
  }
68
 
69
  /**
70
+ * @param array $aOptionsParams
71
  * @return array
72
+ * @throws Exception
73
  */
74
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
+ $sSectionSlug = $aOptionsParams['section_slug'];
77
+ switch( $aOptionsParams['section_slug'] ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ case 'section_enable_plugin_feature_login_protection' :
80
+ $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), $this->getMainFeatureName() );
81
+ break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
+ case 'section_bypass_login_protection' :
84
+ $sTitle = _wpsf__('By-Pass Login Protection');
85
+ break;
86
+
87
+ case 'section_two_factor_authentication' :
88
+ $sTitle = _wpsf__('Two-Factor Authentication');
89
+ break;
90
+
91
+ case 'section_brute_force_login_protection' :
92
+ $sTitle = _wpsf__('Brute Force Login Protection');
93
+ break;
94
+
95
+ case 'section_yubikey_authentication' :
96
+ $sTitle = _wpsf__('Yubikey Authentication');
97
+ break;
98
+
99
+ case 'section_login_logging' :
100
+ $sTitle = _wpsf__('Logging');
101
+ break;
102
+
103
+ default:
104
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
105
+ }
106
+ $aOptionsParams['section_title'] = $sTitle;
107
+ return $aOptionsParams;
108
  }
109
 
110
  /**
111
+ * @param array $aOptionsParams
112
  * @return array
113
+ * @throws Exception
114
  */
115
+ protected function loadStrings_Options( $aOptionsParams ) {
116
+
117
+ $oDp = $this->loadDataProcessor();
118
+ $sKey = $aOptionsParams['key'];
119
+ switch( $sKey ) {
120
+
121
+ case 'enable_login_protect' :
122
+ $sName = sprintf( _wpsf__( 'Enable %s' ), $this->getMainFeatureName() );
123
+ $sSummary = sprintf( _wpsf__( 'Enable (or Disable) The %s Feature' ), $this->getMainFeatureName() );
124
+ $sDescription = sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), $this->getMainFeatureName() );
125
+ break;
126
+
127
+ case 'enable_xmlrpc_compatibility' :
128
+ $sName = _wpsf__( 'XML-RPC Compatibility' );
129
+ $sSummary = _wpsf__( 'Allow Login Through XML-RPC To By-Pass Login Protection Rules' );
130
+ $sDescription = _wpsf__( 'Enable this if you need XML-RPC functionality e.g. if you use the WordPress iPhone/Android App.' );
131
+ break;
132
+
133
+ case 'ips_whitelist' :
134
+ $sName = _wpsf__( 'Whitelist IP Addresses' );
135
+ $sSummary = _wpsf__( 'Specify IP Addresses that by-pass all Login Protect rules' );
136
+ $sDescription = sprintf(
137
+ _wpsf__( 'Take a new line per address. Your IP address is: %s' ),
138
+ '<span class="code">'.( $oDp->GetVisitorIpAddress( false ) ).'</span>'
139
+ );
140
+ break;
141
+
142
+ case 'two_factor_auth_user_roles' :
143
+ $sName = _wpsf__( 'Two-Factor Auth User Roles' );
144
+ $sSummary = _wpsf__( 'All User Roles Subject To Two-Factor Authentication' );
145
+ $sDescription = _wpsf__( 'Select which types of users/roles will be subject to two-factor login authentication.' );
146
+ break;
147
+
148
+ case 'enable_two_factor_auth_by_ip' :
149
+ $sName = sprintf( _wpsf__( 'Two-Factor Authentication (%s)' ), _wpsf__('IP') );
150
+ $sSummary = sprintf( _wpsf__( 'Two-Factor Login Authentication By %s' ), _wpsf__('IP Address') );
151
+ $sDescription = _wpsf__( 'All users will be required to authenticate their login by email-based two-factor authentication, when logging in from a new IP address' );
152
+ break;
153
+
154
+ case 'enable_two_factor_auth_by_cookie' :
155
+ $sName = sprintf( _wpsf__( 'Two-Factor Authentication (%s)' ), _wpsf__('Cookie') );
156
+ $sSummary = sprintf( _wpsf__( 'Two-Factor Login Authentication By %s' ), _wpsf__('Cookie') );
157
+ $sDescription = _wpsf__( 'This will restrict all user login sessions to a single browser. Use this if your users have dynamic IP addresses.' );
158
+ break;
159
+
160
+ case 'enable_two_factor_bypass_on_email_fail' :
161
+ $sName = _wpsf__( 'By-Pass On Failure' );
162
+ $sSummary = _wpsf__( 'If Sending Verification Email Sending Fails, Two-Factor Login Authentication Is Ignored' );
163
+ $sDescription = _wpsf__( 'If you enable two-factor authentication and sending the email with the verification link fails, turning this setting on will by-pass the verification step. Use with caution.' );
164
+ break;
165
+
166
+ case 'login_limit_interval' :
167
+ $sName = _wpsf__('Login Cooldown Interval');
168
+ $sSummary = _wpsf__('Limit login attempts to every X seconds');
169
+ $sDescription = _wpsf__( 'WordPress will process only ONE login attempt for every number of seconds specified.' )
170
+ .'<br />'._wpsf__( 'Zero (0) turns this off.' )
171
+ .' '.sprintf( _wpsf__( 'Default: "%s".' ), $this->getOptionsVo()->getOptDefault( 'login_limit_interval' ) );
172
+ break;
173
+
174
+ case 'enable_login_gasp_check' :
175
+ $sName = _wpsf__( 'G.A.S.P Protection' );
176
+ $sSummary = _wpsf__( 'Use G.A.S.P. Protection To Prevent Login Attempts By Bots' );
177
+ $sDescription = _wpsf__( 'Adds a dynamically (Javascript) generated checkbox to the login form that prevents bots using automated login techniques. Recommended: ON' );
178
+ break;
179
+
180
+ case 'enable_prevent_remote_post' :
181
+ $sName = _wpsf__( 'Prevent Remote Login' );
182
+ $sSummary = _wpsf__( 'Prevents Remote Login Attempts From Anywhere Except Your Site' );
183
+ $sDescription = _wpsf__( 'Prevents any login attempts that do not originate from your website. This prevent bots from attempting to login remotely. Recommended: ON' );
184
+ break;
185
+
186
+ case 'enable_yubikey' :
187
+ $sName = _wpsf__('Enable Yubikey Authentication');
188
+ $sSummary = _wpsf__('Turn On / Off Yubikey Authentication On This Site');
189
+ $sDescription = _wpsf__('Combined with your Yubikey API Key (below) this will form the basis of your Yubikey Authentication');
190
+ break;
191
+
192
+ case 'yubikey_app_id' :
193
+ $sName = _wpsf__( 'Yubikey App ID' );
194
+ $sSummary = _wpsf__( 'Your Unique Yubikey App ID' );
195
+ $sDescription = _wpsf__( 'Combined with your Yubikey API Key this will form the basis of your Yubikey Authentication' )
196
+ . _wpsf__( 'Please review the info link on how to obtain your own Yubikey App ID and API Key.' );
197
+ break;
198
+
199
+ case 'yubikey_api_key' :
200
+ $sName = _wpsf__( 'Yubikey API Key' );
201
+ $sSummary = _wpsf__( 'Your Unique Yubikey App API Key' );
202
+ $sDescription = _wpsf__( 'Combined with your Yubikey App ID this will form the basis of your Yubikey Authentication.' )
203
+ . _wpsf__( 'Please review the info link on how to get your own Yubikey App ID and API Key.' );
204
+ break;
205
+
206
+ case 'yubikey_unique_keys' :
207
+ $sName = _wpsf__( 'Yubikey Unique Keys' );
208
+ $sSummary = _wpsf__( 'Permitted "Username - Yubikey" Pairs For This Site' );
209
+ $sDescription = '<strong>'. sprintf( _wpsf__( 'Format: %s' ), 'Username,Yubikey' ).'</strong>'
210
+ .'<br />- '. _wpsf__( 'Provide Username<->Yubikey Pairs that are usable for this site.')
211
+ .'<br />- '. _wpsf__( 'If a Username if not assigned a Yubikey, Yubikey Authentication is OFF for that user.' )
212
+ .'<br />- '. _wpsf__( 'Each [Username,Key] pair should be separated by a new line: you only need to provide the first 12 characters of the yubikey.' );
213
+ break;
214
+
215
+ case 'enable_login_protect_log' :
216
+ $sName = _wpsf__( 'Login Protect Logging' );
217
+ $sSummary = _wpsf__( 'Turn on a detailed Login Protect Log' );
218
+ $sDescription = _wpsf__( 'Will log every event related to login protection and how it is processed. ' )
219
+ .'<br />'. _wpsf__( 'Not recommended to leave on unless you want to debug something and check the login protection is working as you expect.' );
220
+ break;
221
+
222
+ default:
223
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
224
+ }
225
+
226
+ $aOptionsParams['name'] = $sName;
227
+ $aOptionsParams['summary'] = $sSummary;
228
+ $aOptionsParams['description'] = $sDescription;
229
+ return $aOptionsParams;
230
  }
231
 
232
  /**
233
  * @return bool|void
234
  */
235
+ public function doExtraSubmitProcessing() {
 
 
 
 
 
236
  // When they've clicked to terminate all logged in authenticated users.
237
+ $oDp = $this->loadDataProcessor();
238
+ if ( $oDp->FetchPost( 'terminate-all-logins' ) ) {
239
  $oProc = $this->getProcessor();
240
  $oProc->doTerminateAllVerifiedLogins();
241
  return;
258
  if ( $fAsDefaults ) {
259
  unset($aTwoAuthRoles['type']);
260
  unset($aTwoAuthRoles[0]);
261
+ return array_keys( $aTwoAuthRoles );
262
  }
263
  return $aTwoAuthRoles;
264
  }
265
 
266
+ /**
267
+ * @return string
268
+ */
269
+ public function getLastLoginTimeFilePath() {
270
+ // we always update it (but it wont need saved because we compare)
271
+ $this->setOpt( 'last_login_time_file_path', $this->getController()->getRootDir().'mode.login_throttled' );
272
+ return $this->getOpt( 'last_login_time_file_path' );
273
+ }
274
+
275
  /**
276
  * @return string
277
  */
292
  return $sKey;
293
  }
294
 
295
+ /**
296
+ * @return string
297
+ */
298
+ public function getTwoFactorAuthTableName() {
299
+ return $this->doPluginPrefix( $this->getOpt( 'two_factor_auth_table_name' ), '_' );
300
+ }
301
+
302
+ /**
303
+ * @return string
304
+ */
305
+ public function getTwoFactorAuthCookieName() {
306
+ return $this->getOpt( 'two_factor_auth_cookie_name' );
307
+ }
308
+
309
  /**
310
  * @return string
311
  */
317
  }
318
  return $sKey;
319
  }
320
+
321
+ /**
322
+ * @param string $sType can be either 'ip' or 'cookie'. If empty, both are checked looking for either.
323
+ * @return bool
324
+ */
325
+ public function getIsTwoFactorAuthOn( $sType = '' ) {
326
+
327
+ $fIp = $this->getOptIs( 'enable_two_factor_auth_by_ip', 'Y' );
328
+ $fCookie = $this->getOptIs( 'enable_two_factor_auth_by_cookie', 'Y' );
329
+
330
+ switch( $sType ) {
331
+ case 'ip':
332
+ return $fIp;
333
+ break;
334
+ case 'cookie':
335
+ return $fCookie;
336
+ break;
337
+ default:
338
+ return $fIp || $fCookie;
339
+ break;
340
+ }
341
+ }
342
  }
343
 
344
  endif;
src/icwp-optionshandler-plugin.php CHANGED
@@ -21,10 +21,8 @@ if ( !class_exists('ICWP_WPSF_FeatureHandler_Plugin') ):
21
 
22
  class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
- const Default_AccessKeyTimeout = 30;
25
-
26
  /**
27
- * @var ICWP_WPSF_PluginProcessor
28
  */
29
  protected $oFeatureProcessor;
30
 
@@ -38,16 +36,54 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_Base {
38
  }
39
 
40
  /**
41
- * @return ICWP_WPSF_PluginProcessor|null
42
  */
43
  protected function loadFeatureProcessor() {
44
  if ( !isset( $this->oFeatureProcessor ) ) {
45
- require_once( dirname(__FILE__).'/icwp-processor-plugin.php' );
46
- $this->oFeatureProcessor = new ICWP_WPSF_PluginProcessor( $this );
47
  }
48
  return $this->oFeatureProcessor;
49
  }
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  /**
52
  * @return mixed
53
  */
@@ -75,8 +111,6 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_Base {
75
  $aPluginSummaryData = apply_filters( $this->doPluginPrefix( 'get_feature_summary_data' ), array() );
76
 
77
  $aData = array(
78
- 'aAllOptions' => $this->getOptions(),
79
- 'all_options_input' => $this->collateAllFormInputsForAllOptions(),
80
  'aSummaryData' => $aPluginSummaryData
81
  );
82
  $aData = array_merge( $this->getBaseDisplayData(), $aData );
@@ -85,12 +119,16 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_Base {
85
 
86
  /**
87
  * Hooked to 'deactivate_plugin' and can be used to interrupt the deactivation of this plugin.
88
- * @param string $insPlugin
 
89
  */
90
- public function onWpHookDeactivatePlugin( $insPlugin ) {
91
- if ( strpos( $this->oPluginVo->getRootFile(), $insPlugin ) !== false ) {
92
  if ( !apply_filters( $this->doPluginPrefix( 'has_permission_to_submit' ), true ) ) {
93
- wp_die( 'Sorry, you do not have permission to disable this plugin. You need to authenticate first.' );
 
 
 
94
  }
95
  }
96
  }
@@ -108,76 +146,68 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_Base {
108
  }
109
 
110
  /**
 
111
  * @return array
 
112
  */
113
- protected function getOptionsDefinitions() {
114
- $aGeneral = array(
115
- 'section_title' => _wpsf__( 'General Plugin Options' ),
116
- 'section_options' => array(
117
- array(
118
- 'block_send_email_address',
119
- '',
120
- '',
121
- 'email',
122
- _wpsf__( 'Report Email' ),
123
- _wpsf__( 'Where to send email reports from the Firewall' ),
124
- _wpsf__( 'If this is empty, it will default to the blog admin email address' )
125
- ),
126
- array(
127
- 'enable_upgrade_admin_notice',
128
- '',
129
- 'Y',
130
- 'checkbox',
131
- _wpsf__( 'Plugin Notices' ),
132
- _wpsf__( 'Display Notices For Updates' ),
133
- _wpsf__( 'Disable this option to hide certain plugin admin notices about available updates and post-update notices' )
134
- ),
135
- array(
136
- 'delete_on_deactivate',
137
- '',
138
- 'N',
139
- 'checkbox',
140
- _wpsf__( 'Delete Plugin Settings' ),
141
- _wpsf__( 'Delete All Plugin Settings Upon Plugin Deactivation' ),
142
- _wpsf__( 'Careful: Removes all plugin options when you deactivate the plugin' )
143
- )
144
- )
145
- );
146
 
147
- $aOptionsDefinitions = array(
148
- $aGeneral
149
- );
150
- return $aOptionsDefinitions;
 
 
 
 
 
 
 
 
151
  }
152
 
153
  /**
 
154
  * @return array
 
155
  */
156
- protected function getNonUiOptions() {
157
- $aNonUiOptions = array(
158
- 'installation_time',
159
- 'secret_key',
160
- 'feedback_admin_notice',
161
- 'update_success_tracker',
162
- 'capability_can_disk_write',
163
- 'capability_can_remote_get'
164
- );
165
- return $aNonUiOptions;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  }
167
-
168
  /**
169
  * This is the point where you would want to do any options verification
170
  */
171
  protected function doPrePluginOptionsSave() {
172
-
173
- if ( $this->getOpt( 'admin_access_key_timeout' ) <= 0 ) {
174
- $this->setOpt( 'admin_access_key_timeout', self::Default_AccessKeyTimeout );
175
- }
176
-
177
- $sAccessKey = $this->getOpt( 'admin_access_key');
178
- if ( empty( $sAccessKey ) ) {
179
- $this->setOpt( 'enable_admin_access_restriction', 'N' );
180
- }
181
 
182
  $this->setOpt( 'enable_logging', 'Y' );
183
 
@@ -189,10 +219,30 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_Base {
189
 
190
  protected function updateHandler() {
191
  parent::updateHandler();
 
 
 
 
 
192
  if ( version_compare( $this->getVersion(), '3.0.0', '<' ) ) {
193
  $aAllOptions = apply_filters( $this->doPluginPrefix( 'aggregate_all_plugin_options' ), array() );
194
  $this->setOpt( 'block_send_email_address', $aAllOptions['block_send_email_address'] );
195
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  }
197
  }
198
 
21
 
22
  class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_Base {
23
 
 
 
24
  /**
25
+ * @var ICWP_WPSF_Processor_Plugin
26
  */
27
  protected $oFeatureProcessor;
28
 
36
  }
37
 
38
  /**
39
+ * @return ICWP_WPSF_Processor_Plugin|null
40
  */
41
  protected function loadFeatureProcessor() {
42
  if ( !isset( $this->oFeatureProcessor ) ) {
43
+ require_once( $this->getController()->getSourceDir().'icwp-processor-plugin.php' );
44
+ $this->oFeatureProcessor = new ICWP_WPSF_Processor_Plugin( $this );
45
  }
46
  return $this->oFeatureProcessor;
47
  }
48
 
49
+ /**
50
+ */
51
+ public function doClearAdminFeedback() {
52
+ $this->setOpt( 'feedback_admin_notice', array() );
53
+ }
54
+
55
+ /**
56
+ * @param string $sMessage
57
+ */
58
+ public function doAddAdminFeedback( $sMessage ) {
59
+ $aFeedback = $this->getOpt( 'feedback_admin_notice', array() );
60
+ $aFeedback[] = $sMessage;
61
+ $this->setOpt( 'feedback_admin_notice', $aFeedback );
62
+ }
63
+
64
+ public function doExtraSubmitProcessing() {
65
+ $this->doAddAdminFeedback( sprintf( _wpsf__( '%s Plugin options updated successfully.' ), $this->getController()->getHumanName() ) );
66
+ }
67
+
68
+ /**
69
+ * @return array
70
+ */
71
+ public function getActivePluginFeatures() {
72
+ $aActiveFeatures = $this->getOptionsVo()->getRawData_SingleOption( 'active_plugin_features' );
73
+ $aPluginFeatures = array();
74
+ if ( empty( $aActiveFeatures['value'] ) || !is_array( $aActiveFeatures['value'] ) ) {
75
+ return $aPluginFeatures;
76
+ }
77
+
78
+ foreach( $aActiveFeatures['value'] as $aFeature ) {
79
+ if ( isset( $aFeature['hidden'] ) && $aFeature['hidden'] ) {
80
+ continue;
81
+ }
82
+ $aPluginFeatures[ $aFeature['slug'] ] = $aFeature['storage_key'];
83
+ }
84
+ return $aPluginFeatures;
85
+ }
86
+
87
  /**
88
  * @return mixed
89
  */
111
  $aPluginSummaryData = apply_filters( $this->doPluginPrefix( 'get_feature_summary_data' ), array() );
112
 
113
  $aData = array(
 
 
114
  'aSummaryData' => $aPluginSummaryData
115
  );
116
  $aData = array_merge( $this->getBaseDisplayData(), $aData );
119
 
120
  /**
121
  * Hooked to 'deactivate_plugin' and can be used to interrupt the deactivation of this plugin.
122
+ *
123
+ * @param string $sPlugin
124
  */
125
+ public function onWpHookDeactivatePlugin( $sPlugin ) {
126
+ if ( strpos( $this->getController()->getRootFile(), $sPlugin ) !== false ) {
127
  if ( !apply_filters( $this->doPluginPrefix( 'has_permission_to_submit' ), true ) ) {
128
+ wp_die(
129
+ _wpsf__( 'Sorry, you do not have permission to disable this plugin.')
130
+ . _wpsf__( 'You need to authenticate first.' )
131
+ );
132
  }
133
  }
134
  }
146
  }
147
 
148
  /**
149
+ * @param array $aOptionsParams
150
  * @return array
151
+ * @throws Exception
152
  */
153
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
+ $sSectionSlug = $aOptionsParams['section_slug'];
156
+ switch( $aOptionsParams['section_slug'] ) {
157
+
158
+ case 'section_general_plugin_options' :
159
+ $sTitle = _wpsf__( 'General Plugin Options' );
160
+ break;
161
+
162
+ default:
163
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
164
+ }
165
+ $aOptionsParams['section_title'] = $sTitle;
166
+ return $aOptionsParams;
167
  }
168
 
169
  /**
170
+ * @param array $aOptionsParams
171
  * @return array
172
+ * @throws Exception
173
  */
174
+ protected function loadStrings_Options( $aOptionsParams ) {
175
+
176
+ $sKey = $aOptionsParams['key'];
177
+ switch( $sKey ) {
178
+
179
+ case 'block_send_email_address' :
180
+ $sName = _wpsf__( 'Report Email' );
181
+ $sSummary = _wpsf__( 'Where to send email reports' );
182
+ $sDescription = sprintf( _wpsf__( 'If this is empty, it will default to the blog admin email address: %s' ), '<br /><strong>'.get_bloginfo('admin_email').'</strong>' );
183
+ break;
184
+
185
+ case 'enable_upgrade_admin_notice' :
186
+ $sName = _wpsf__( 'Plugin Notices' );
187
+ $sSummary = _wpsf__( 'Display Notices For Updates' );
188
+ $sDescription = _wpsf__( 'Disable this option to hide certain plugin admin notices about available updates and post-update notices' );
189
+ break;
190
+
191
+ case 'delete_on_deactivate' :
192
+ $sName = _wpsf__( 'Delete Plugin Settings' );
193
+ $sSummary = _wpsf__( 'Delete All Plugin Settings Upon Plugin Deactivation' );
194
+ $sDescription = _wpsf__( 'Careful: Removes all plugin options when you deactivate the plugin' );
195
+ break;
196
+
197
+ default:
198
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
199
+ }
200
+
201
+ $aOptionsParams['name'] = $sName;
202
+ $aOptionsParams['summary'] = $sSummary;
203
+ $aOptionsParams['description'] = $sDescription;
204
+ return $aOptionsParams;
205
  }
206
+
207
  /**
208
  * This is the point where you would want to do any options verification
209
  */
210
  protected function doPrePluginOptionsSave() {
 
 
 
 
 
 
 
 
 
211
 
212
  $this->setOpt( 'enable_logging', 'Y' );
213
 
219
 
220
  protected function updateHandler() {
221
  parent::updateHandler();
222
+
223
+ if ( $this->getVersion() == '0.0' ) {
224
+ return;
225
+ }
226
+
227
  if ( version_compare( $this->getVersion(), '3.0.0', '<' ) ) {
228
  $aAllOptions = apply_filters( $this->doPluginPrefix( 'aggregate_all_plugin_options' ), array() );
229
  $this->setOpt( 'block_send_email_address', $aAllOptions['block_send_email_address'] );
230
  }
231
+
232
+ // clean out old database tables as we've changed the naming prefix going forward.
233
+ if ( version_compare( $this->getVersion(), '3.5.0', '<' ) ) {
234
+ $aOldTables = array(
235
+ 'icwp_wpsf_log',
236
+ 'icwp_login_auth',
237
+ 'icwp_comments_filter',
238
+ 'icwp_user_management'
239
+ );
240
+ global $wpdb;
241
+ foreach( $aOldTables as $sTable ) {
242
+ $sQuery = sprintf( 'DROP TABLE IF EXISTS `%s%s`', $wpdb->prefix, $sTable ) ;
243
+ $wpdb->query( $sQuery );
244
+ }
245
+ }
246
  }
247
  }
248
 
src/icwp-optionshandler-privacy_protect.php CHANGED
@@ -22,7 +22,7 @@ if ( !class_exists('ICWP_WPSF_FeatureHandler_PrivacyProtect') ):
22
  class ICWP_WPSF_FeatureHandler_PrivacyProtect extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
  /**
25
- * @var ICWP_WPSF_PrivacyProtectProcessor
26
  */
27
  protected $oFeatureProcessor;
28
 
@@ -33,25 +33,23 @@ class ICWP_WPSF_FeatureHandler_PrivacyProtect extends ICWP_WPSF_FeatureHandler_B
33
  }
34
 
35
  /**
36
- * @return ICWP_WPSF_PrivacyProtectProcessor|null
37
  */
38
  protected function loadFeatureProcessor() {
39
  if ( !isset( $this->oFeatureProcessor ) ) {
40
- require_once( dirname(__FILE__).'/icwp-processor-privacyprotect.php' );
41
- $this->oFeatureProcessor = new ICWP_WPSF_PrivacyProtectProcessor( $this );
42
  }
43
  return $this->oFeatureProcessor;
44
  }
45
 
46
- public function doPrePluginOptionsSave() { }
47
-
48
  /**
49
  * @return array
50
  */
51
  protected function getOptionsDefinitions() {
52
 
53
  $aOptionsBase = array(
54
- 'section_title' => _wpsf__( 'Enable Privacy Protection' ),
55
  'section_options' => array(
56
  array(
57
  'enable_privacy_protect',
@@ -63,7 +61,7 @@ class ICWP_WPSF_FeatureHandler_PrivacyProtect extends ICWP_WPSF_FeatureHandler_B
63
  _wpsf__( 'Regardless of any other settings, this option will turn off the Privacy Protection feature, or enable your selected Privacy Protection options' ),
64
  '<a href="http://icwp.io/3y" target="_blank">'._wpsf__( 'more info' ).'</a>'
65
  )
66
- ),
67
  );
68
  $aFurtherOptions = array(
69
  'section_title' => _wpsf__( 'Data Filtering and Logging Options' ),
@@ -108,13 +106,9 @@ class ICWP_WPSF_FeatureHandler_PrivacyProtect extends ICWP_WPSF_FeatureHandler_B
108
  return $aOptionsDefinitions;
109
  }
110
 
111
- public function handleFormSubmit() {
112
- if ( !parent::handleFormSubmit() ) {
113
- return false;
114
- }
115
- $this->loadDataProcessor();
116
-
117
- if ( ICWP_WPSF_DataProcessor::FetchPost( 'clear_log_submit' ) ) {
118
  $oLoggingProcessor = $this->getLoggingProcessor();
119
  $oLoggingProcessor->recreateTable();
120
  return true;
22
  class ICWP_WPSF_FeatureHandler_PrivacyProtect extends ICWP_WPSF_FeatureHandler_Base {
23
 
24
  /**
25
+ * @var ICWP_WPSF_Processor_PrivacyProtect
26
  */
27
  protected $oFeatureProcessor;
28
 
33
  }
34
 
35
  /**
36
+ * @return ICWP_WPSF_Processor_PrivacyProtect|null
37
  */
38
  protected function loadFeatureProcessor() {
39
  if ( !isset( $this->oFeatureProcessor ) ) {
40
+ require_once( $this->getController()->getSourceDir( sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) ) );
41
+ $this->oFeatureProcessor = new ICWP_WPSF_Processor_PrivacyProtect( $this );
42
  }
43
  return $this->oFeatureProcessor;
44
  }
45
 
 
 
46
  /**
47
  * @return array
48
  */
49
  protected function getOptionsDefinitions() {
50
 
51
  $aOptionsBase = array(
52
+ 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('Privacy Protection') ),
53
  'section_options' => array(
54
  array(
55
  'enable_privacy_protect',
61
  _wpsf__( 'Regardless of any other settings, this option will turn off the Privacy Protection feature, or enable your selected Privacy Protection options' ),
62
  '<a href="http://icwp.io/3y" target="_blank">'._wpsf__( 'more info' ).'</a>'
63
  )
64
+ )
65
  );
66
  $aFurtherOptions = array(
67
  'section_title' => _wpsf__( 'Data Filtering and Logging Options' ),
106
  return $aOptionsDefinitions;
107
  }
108
 
109
+ protected function doExtraSubmitProcessing() {
110
+ $oDp = $this->loadDataProcessor();
111
+ if ( $oDp->FetchPost( 'clear_log_submit' ) ) {
 
 
 
 
112
  $oLoggingProcessor = $this->getLoggingProcessor();
113
  $oLoggingProcessor->recreateTable();
114
  return true;
src/icwp-optionshandler-user_management.php CHANGED
@@ -20,6 +20,8 @@ require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
20
  if ( !class_exists('ICWP_WPSF_FeatureHandler_UserManagement') ):
21
 
22
  class ICWP_WPSF_FeatureHandler_UserManagement extends ICWP_WPSF_FeatureHandler_Base {
 
 
23
 
24
  /**
25
  * @var ICWP_WPSF_Processor_UserManagement
@@ -37,12 +39,29 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends ICWP_WPSF_FeatureHandler_B
37
  */
38
  protected function loadFeatureProcessor() {
39
  if ( !isset( $this->oFeatureProcessor ) ) {
40
- require_once( dirname(__FILE__).'/icwp-processor-usermanagement.php' );
41
  $this->oFeatureProcessor = new ICWP_WPSF_Processor_UserManagement( $this );
42
  }
43
  return $this->oFeatureProcessor;
44
  }
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  /**
47
  */
48
  public function displayFeatureConfigPage( ) {
@@ -59,74 +78,137 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends ICWP_WPSF_FeatureHandler_B
59
  $aData = array_merge( $this->getBaseDisplayData(), $aData );
60
  $this->display( $aData );
61
  }
62
-
63
- public function doPrePluginOptionsSave() { }
64
 
65
  /**
 
66
  * @return array
 
67
  */
68
- protected function getOptionsDefinitions() {
69
- $aOptionsBase = array(
70
- 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('User Accounts Management') ),
71
- 'section_options' => array(
72
- array(
73
- 'enable_user_management',
74
- '',
75
- 'N',
76
- 'checkbox',
77
- _wpsf__( 'Enable User Accounts Management' ),
78
- _wpsf__( 'Enable (or Disable) The User Accounts Management Feature' ),
79
- sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('User Accounts Management') ),
80
- )
81
- ),
82
- );
83
 
84
- $aSessions = array(
85
- 'section_title' => _wpsf__( 'User Session Management' ),
86
- 'section_options' => array(
87
- array(
88
- 'session_timeout_interval',
89
- '',
90
- '2',
91
- 'integer',
92
- _wpsf__( 'Session Timeout' ),
93
- _wpsf__( 'Specify How Many Days After Login To Automatically Force Re-Login' ),
94
- sprintf( _wpsf__( 'WordPress default is 2 days, or 14 days if you check the "Remember Me" box.' ), '<span class="code">'.$this->getVisitorIpAddress( false ).'</span>' )
95
- ),
96
- array(
97
- 'session_idle_timeout_interval',
98
- '',
99
- '0',
100
- 'integer',
101
- _wpsf__( 'Idle Timeout' ),
102
- _wpsf__( 'Specify How Many Hours After Inactivity To Automatically Logout User' ),
103
- _wpsf__( 'If the user is inactive for the number of hours specified, they will be forcefully logged out next time they return.' )
104
- ),
105
- array(
106
- 'session_lock_location',
107
- '',
108
- 'N',
109
- 'checkbox',
110
- _wpsf__( 'Lock To Location' ),
111
- _wpsf__( 'Locks A User Session To IP address' ),
112
- _wpsf__( 'Restricts login to any account to a location as determined by IP address.' )
113
- )
114
- )
115
- );
116
 
117
- $aOptionsDefinitions = array(
118
- $aOptionsBase,
119
- $aSessions
120
- );
121
- return $aOptionsDefinitions;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  }
123
 
124
  /**
 
125
  * @return array
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  */
127
- protected function getNonUiOptions() {
128
- $aNonUiOptions = array();
129
- return $aNonUiOptions;
130
  }
131
  }
132
 
20
  if ( !class_exists('ICWP_WPSF_FeatureHandler_UserManagement') ):
21
 
22
  class ICWP_WPSF_FeatureHandler_UserManagement extends ICWP_WPSF_FeatureHandler_Base {
23
+
24
+ const UserManagementTableName = 'user_management';
25
 
26
  /**
27
  * @var ICWP_WPSF_Processor_UserManagement
39
  */
40
  protected function loadFeatureProcessor() {
41
  if ( !isset( $this->oFeatureProcessor ) ) {
42
+ require_once( $this->getController()->getSourceDir( sprintf( 'icwp-processor-%s.php', $this->getFeatureSlug() ) ) );
43
  $this->oFeatureProcessor = new ICWP_WPSF_Processor_UserManagement( $this );
44
  }
45
  return $this->oFeatureProcessor;
46
  }
47
 
48
+ /**
49
+ */
50
+ public function doPrePluginOptionsSave() {
51
+
52
+ if ( !is_email( $this->getOpt( 'enable_admin_login_email_notification' ) ) ) {
53
+ $this->getOptionsVo()->resetOptToDefault( 'enable_admin_login_email_notification' );
54
+ }
55
+
56
+ if ( $this->getOpt( 'session_username_concurrent_limit' ) < 0 ) {
57
+ $this->getOptionsVo()->resetOptToDefault( 'session_username_concurrent_limit' );
58
+ }
59
+
60
+ if ( $this->getOpt( 'session_timeout_interval' ) < 1 ) {
61
+ $this->getOptionsVo()->resetOptToDefault( 'session_timeout_interval' );
62
+ }
63
+ }
64
+
65
  /**
66
  */
67
  public function displayFeatureConfigPage( ) {
78
  $aData = array_merge( $this->getBaseDisplayData(), $aData );
79
  $this->display( $aData );
80
  }
 
 
81
 
82
  /**
83
+ * @param array $aOptionsParams
84
  * @return array
85
+ * @throws Exception
86
  */
87
+ protected function loadStrings_SectionTitles( $aOptionsParams ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
+ $sSectionSlug = $aOptionsParams['section_slug'];
90
+ switch( $aOptionsParams['section_slug'] ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
+ case 'section_enable_plugin_feature_user_accounts_management' :
93
+ $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), $this->getMainFeatureName() );
94
+ break;
95
+
96
+ case 'section_bypass_user_accounts_management' :
97
+ $sTitle = _wpsf__('By-Pass User Accounts Management');
98
+ break;
99
+
100
+ case 'section_admin_login_notification' :
101
+ $sTitle = _wpsf__('Admin Login Notification');
102
+ break;
103
+
104
+ case 'section_user_session_management' :
105
+ $sTitle = _wpsf__('User Session Management');
106
+ break;
107
+
108
+ case 'section_automatic_update_email_notifications' :
109
+ $sTitle = _wpsf__('Automatic Update Email Notifications');
110
+ break;
111
+
112
+ default:
113
+ throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
114
+ }
115
+ $aOptionsParams['section_title'] = $sTitle;
116
+ return $aOptionsParams;
117
  }
118
 
119
  /**
120
+ * @param array $aOptionsParams
121
  * @return array
122
+ * @throws Exception
123
+ */
124
+ protected function loadStrings_Options( $aOptionsParams ) {
125
+
126
+ $sKey = $aOptionsParams['key'];
127
+ switch( $sKey ) {
128
+
129
+ case 'enable_user_management' :
130
+ $sName = sprintf( _wpsf__( 'Enable %s' ), $this->getMainFeatureName() );
131
+ $sSummary = sprintf( _wpsf__( 'Enable (or Disable) The %s Feature' ), $this->getMainFeatureName() );
132
+ $sDescription = sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), $this->getMainFeatureName() );
133
+ break;
134
+
135
+ case 'enable_xmlrpc_compatibility' :
136
+ $sName = _wpsf__( 'XML-RPC Compatibility' );
137
+ $sSummary = _wpsf__( 'Allow Login Through XML-RPC To By-Pass Accounts Management Rules' );
138
+ $sDescription = _wpsf__( 'Enable this if you need XML-RPC functionality e.g. if you use the WordPress iPhone/Android App.' );
139
+ break;
140
+
141
+ case 'enable_admin_login_email_notification' :
142
+ $sName = _wpsf__( 'Admin Login Notification Email' );
143
+ $sSummary = _wpsf__( 'Send An Notification Email When Administrator Logs In' );
144
+ $sDescription = _wpsf__( 'If you would like to be notified every time an administrator user logs into this WordPress site, enter a notification email address.' )
145
+ .'<br />'._wpsf__( 'No email address - No Notification.' );
146
+ break;
147
+
148
+ case 'session_timeout_interval' :
149
+ $sName = _wpsf__( 'Session Timeout' );
150
+ $sSummary = _wpsf__( 'Specify How Many Days After Login To Automatically Force Re-Login' );
151
+ $sDescription = _wpsf__( 'WordPress default is 2 days, or 14 days if you check the "Remember Me" box.' )
152
+ .'<br />'. sprintf( _wpsf__( 'This cannot be less than %s.' ), '"<strong>1</strong>"' )
153
+ .'<br />'. sprintf( _wpsf__( 'Default: %s.' ), '"<strong>'.$this->getOptionsVo()->getOptDefault('session_timeout_interval').'</strong>"' );
154
+ break;
155
+
156
+ case 'session_idle_timeout_interval' :
157
+ $sName = _wpsf__( 'Idle Timeout' );
158
+ $sSummary = _wpsf__( 'Specify How Many Hours After Inactivity To Automatically Logout User' );
159
+ $sDescription = _wpsf__( 'If the user is inactive for the number of hours specified, they will be forcefully logged out next time they return.' )
160
+ .'<br />'. sprintf( _wpsf__( 'Set to %s to turn off this option.' ), '"<strong>0</strong>"' );
161
+ break;
162
+
163
+ case 'session_lock_location' :
164
+ $sName = _wpsf__( 'Lock To Location' );
165
+ $sSummary = _wpsf__( 'Locks A User Session To IP address' );
166
+ $sDescription = _wpsf__( 'When selected, a session is restricted to the same IP address as when the user logged in.' )
167
+ .' '._wpsf__( "If a logged-in user's IP address changes, the session will be invalidated and they'll be forced to re-login to WordPress." );
168
+ break;
169
+
170
+ case 'session_username_concurrent_limit' :
171
+ $sName = _wpsf__( 'Max Simultaneous Sessions' );
172
+ $sSummary = _wpsf__( 'Limit Simultaneous Sessions For The Same Username' );
173
+ $sDescription = _wpsf__( 'The number provided here is the maximum number of simultaneous, distinct, sessions allowed for any given username.' )
174
+ .'<br />'._wpsf__( "Zero (0) will allow unlimited simultaneous sessions." );
175
+ break;
176
+
177
+ case 'session_check_admin_area_only' :
178
+ $sName = _wpsf__( 'Check Admin Area Only' );
179
+ $sSummary = _wpsf__( 'Perform Session Checking For Logged In Users Only In Admin Area' );
180
+ $sDescription = _wpsf__( 'When selected, session timeouts will only be checked on visits to the WordPress admin area.' );
181
+ break;
182
+
183
+ case 'session_auto_forward_to_admin_area' :
184
+ $sName = _wpsf__( 'Auto Redirect To Admin' );
185
+ $sSummary = _wpsf__( 'Automatically Redirect To WP Admin When Valid Session Detected' );
186
+ $sDescription = _wpsf__( 'When selected, users will be automatically forwarded to the WordPress admin screen when they visit wp-login.php.' )
187
+ .'<br />'. _wpsf__( 'It removes the extra step to get to the admin screen for already-authenticated users.' );
188
+ break;
189
+
190
+ default:
191
+ throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
192
+ }
193
+
194
+ $aOptionsParams['name'] = $sName;
195
+ $aOptionsParams['summary'] = $sSummary;
196
+ $aOptionsParams['description'] = $sDescription;
197
+ return $aOptionsParams;
198
+ }
199
+
200
+ /**
201
+ * @return string
202
+ */
203
+ public function getUserSessionsTableName() {
204
+ return $this->doPluginPrefix( $this->getOpt( 'user_sessions_table_name' ), '_' );
205
+ }
206
+
207
+ /**
208
+ * @return string
209
  */
210
+ public function getUserSessionCookieName() {
211
+ return $this->getOpt( 'user_session_cookie_name' );
 
212
  }
213
  }
214
 
src/{icwp-processor-adminaccessrestriction.php → icwp-processor-admin_access_restriction.php} RENAMED
@@ -15,11 +15,16 @@
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
- require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
  if ( !class_exists('ICWP_WPSF_Processor_AdminAccessRestriction') ):
21
 
22
- class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_BaseProcessor {
 
 
 
 
 
23
 
24
  /**
25
  * @var string
@@ -34,8 +39,8 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_BaseProcessor
34
  }
35
 
36
  public function run() {
37
-
38
- if ( ! $this->oFeatureOptions->getIsUpgrading() ) {
39
  $this->sOptionRegexPattern = '/^'. $this->oFeatureOptions->getOptionStoragePrefix() . '.*_options$/';
40
  add_filter( 'pre_update_option', array( $this, 'blockOptionsSaves' ), 1, 3 );
41
  }
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
 
20
  if ( !class_exists('ICWP_WPSF_Processor_AdminAccessRestriction') ):
21
 
22
+ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction
26
+ */
27
+ protected $oFeatureOptions;
28
 
29
  /**
30
  * @var string
39
  }
40
 
41
  public function run() {
42
+ $oWp = $this->loadWpFunctionsProcessor();
43
+ if ( ! $this->oFeatureOptions->getIsUpgrading() && ! $oWp->getIsLoginRequest() ) {
44
  $this->sOptionRegexPattern = '/^'. $this->oFeatureOptions->getOptionStoragePrefix() . '.*_options$/';
45
  add_filter( 'pre_update_option', array( $this, 'blockOptionsSaves' ), 1, 3 );
46
  }
src/icwp-processor-audit_trail.php ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-basedb.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_AuditTrail_V1') ):
21
+
22
+ class ICWP_WPSF_Processor_AuditTrail_V1 extends ICWP_WPSF_BaseDbProcessor {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_AuditTrail
26
+ */
27
+ protected $oFeatureOptions;
28
+
29
+ /**
30
+ * @param ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions
31
+ */
32
+ public function __construct( ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions ) {
33
+ parent::__construct( $oFeatureOptions, $oFeatureOptions->getAuditTrailTableName() );
34
+ add_action( $this->oFeatureOptions->doPluginPrefix( 'plugin_shutdown' ), array( $this, 'commitAuditTrial' ) );
35
+ }
36
+
37
+ /**
38
+ */
39
+ public function run() {
40
+
41
+ if ( $this->getIsOption( 'enable_audit_context_users', 'Y' ) ) {
42
+ require_once( 'icwp-processor-audit_trail_users.php' );
43
+ $oUsers = new ICWP_WPSF_Processor_AuditTrail_Users( $this->oFeatureOptions );
44
+ $oUsers->run();
45
+ }
46
+
47
+ if ( $this->getIsOption( 'enable_audit_context_plugins', 'Y' ) ) {
48
+ require_once( 'icwp-processor-audit_trail_plugins.php' );
49
+ $oUsers = new ICWP_WPSF_Processor_AuditTrail_Plugins( $this->oFeatureOptions );
50
+ $oUsers->run();
51
+ }
52
+
53
+ if ( $this->getIsOption( 'enable_audit_context_themes', 'Y' ) ) {
54
+ require_once( 'icwp-processor-audit_trail_themes.php' );
55
+ $oUsers = new ICWP_WPSF_Processor_AuditTrail_Themes( $this->oFeatureOptions );
56
+ $oUsers->run();
57
+ }
58
+
59
+ if ( $this->getIsOption( 'enable_audit_context_wordpress', 'Y' ) ) {
60
+ require_once( 'icwp-processor-audit_trail_wordpress.php' );
61
+ $oUsers = new ICWP_WPSF_Processor_AuditTrail_Wordpress( $this->oFeatureOptions );
62
+ $oUsers->run();
63
+ }
64
+
65
+ if ( $this->getIsOption( 'enable_audit_context_posts', 'Y' ) ) {
66
+ require_once( 'icwp-processor-audit_trail_posts.php' );
67
+ $oUsers = new ICWP_WPSF_Processor_AuditTrail_Posts( $this->oFeatureOptions );
68
+ $oUsers->run();
69
+ }
70
+ // if ( $this->getIsOption( 'enable_audit_context_wpsf', 'Y' ) ) {
71
+ // require_once( 'icwp-processor-audit_trail_wpsf.php' );
72
+ // $oUsers = new ICWP_WPSF_Processor_AuditTrail_Wpsf( $this->oFeatureOptions );
73
+ // $oUsers->run();
74
+ // }
75
+ }
76
+
77
+ /**
78
+ * @return array|bool
79
+ */
80
+ public function getAllAuditEntries() {
81
+ return array_reverse( $this->selectAllFromTable() );
82
+ }
83
+
84
+ /**
85
+ */
86
+ public function commitAuditTrial() {
87
+ $aEntries = $this->getAuditTrailEntries()->getAuditTrailEntries( true );
88
+ if ( empty( $aEntries ) || !is_array( $aEntries ) ) {
89
+ return;
90
+ }
91
+
92
+ foreach( $aEntries as $aEntry ) {
93
+ $this->insertIntoTable( $aEntry );
94
+ }
95
+ }
96
+
97
+ /**
98
+ * @return ICWP_WPSF_AuditTrail_Entries
99
+ */
100
+ protected function getAuditTrailEntries() {
101
+ return ICWP_WPSF_AuditTrail_Entries::GetInstance();
102
+ }
103
+
104
+ /**
105
+ * @return string
106
+ */
107
+ protected function getCreateTableSql() {
108
+ $sSqlTables = "
109
+ CREATE TABLE IF NOT EXISTS `%s` (
110
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
111
+ `wp_username` VARCHAR(255) NOT NULL DEFAULT 'none',
112
+ `context` VARCHAR(25) NOT NULL DEFAULT 'none',
113
+ `event` VARCHAR(25) NOT NULL DEFAULT 'none',
114
+ `category` INT(3) NOT NULL DEFAULT '0',
115
+ `message` TEXT,
116
+ `created_at` INT(15) NOT NULL DEFAULT '0',
117
+ `deleted_at` INT(15) NOT NULL DEFAULT '0',
118
+ PRIMARY KEY (`id`)
119
+ ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
120
+
121
+ return sprintf( $sSqlTables, $this->getTableName() );
122
+ }
123
+ }
124
+
125
+ endif;
126
+
127
+ if ( !class_exists('ICWP_WPSF_Processor_AuditTrail') ):
128
+ class ICWP_WPSF_Processor_AuditTrail extends ICWP_WPSF_Processor_AuditTrail_V1 { }
129
+ endif;
130
+
131
+ class ICWP_WPSF_AuditTrail_Entries {
132
+
133
+ /**
134
+ * @var ICWP_WPSF_AuditTrail_Entries
135
+ */
136
+ protected static $oInstance = NULL;
137
+
138
+ /**
139
+ * @return ICWP_WPSF_AuditTrail_Entries
140
+ */
141
+ public static function GetInstance() {
142
+ if ( is_null( self::$oInstance ) ) {
143
+ self::$oInstance = new self();
144
+ }
145
+ return self::$oInstance;
146
+ }
147
+
148
+ /**
149
+ * @var array
150
+ */
151
+ protected $aEntries;
152
+
153
+ public function add( $sContext, $sEvent, $nCategory, $sMessage = '' ) {
154
+ $oDp = $this->loadDataProcessor();
155
+ $oWp = $this->loadWpFunctionsProcessor();
156
+ $oCurrentUser = $oWp->getCurrentWpUser();
157
+ $aNewEntry = array(
158
+ 'created_at' => $oDp->GetRequestTime(),
159
+ 'wp_username' => empty( $oCurrentUser ) ? 'unknown' : $oCurrentUser->get( 'user_login' ),
160
+ 'context' => $sContext,
161
+ 'event' => $sEvent,
162
+ 'category' => $nCategory,
163
+ 'message' => $sMessage,
164
+ );
165
+ $aEntries = $this->getAuditTrailEntries();
166
+ $aEntries[] = $aNewEntry;
167
+ $this->aEntries = $aEntries;
168
+ }
169
+
170
+ /**
171
+ * For use inside the object
172
+ *
173
+ * @return array
174
+ */
175
+ protected function & getEntries() {
176
+ if ( !isset( $this->aEntries ) ) {
177
+ $this->aEntries = array();
178
+ }
179
+ return $this->aEntries;
180
+ }
181
+
182
+ /**
183
+ * @param boolean $fFlush
184
+ * @return array
185
+ */
186
+ public function getAuditTrailEntries( $fFlush = false ) {
187
+ if ( !isset( $this->aEntries ) ) {
188
+ $this->aEntries = array();
189
+ }
190
+ $aEntries = $this->aEntries;
191
+ if ( $fFlush ) {
192
+ $this->aEntries = array();
193
+ }
194
+ return $aEntries;
195
+ }
196
+
197
+
198
+ /**
199
+ * @return ICWP_WPSF_DataProcessor
200
+ */
201
+ public function loadDataProcessor() {
202
+ if ( !class_exists('ICWP_WPSF_DataProcessor') ) {
203
+ require_once( dirname(__FILE__).'/icwp-data-processor.php' );
204
+ }
205
+ return ICWP_WPSF_DataProcessor::GetInstance();
206
+ }
207
+
208
+ /**
209
+ * @return ICWP_WPSF_WpFilesystem
210
+ */
211
+ public function loadFileSystemProcessor() {
212
+ if ( !class_exists('ICWP_WPSF_WpFilesystem') ) {
213
+ require_once( dirname(__FILE__) . '/icwp-wpfilesystem.php' );
214
+ }
215
+ return ICWP_WPSF_WpFilesystem::GetInstance();
216
+ }
217
+
218
+ /**
219
+ * @return ICWP_WPSF_WpFunctions
220
+ */
221
+ public function loadWpFunctionsProcessor() {
222
+ require_once( dirname(__FILE__) . '/icwp-wpfunctions.php' );
223
+ return ICWP_WPSF_WpFunctions::GetInstance();
224
+ }
225
+ }
src/icwp-processor-audit_trail_plugins.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_AuditTrail_Plugins') ):
21
+
22
+ class ICWP_WPSF_Processor_AuditTrail_Plugins extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_AuditTrail
26
+ */
27
+ protected $oFeatureOptions;
28
+
29
+ /**
30
+ * @param ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions
31
+ */
32
+ public function __construct( ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions ) {
33
+ parent::__construct( $oFeatureOptions );
34
+ }
35
+
36
+ /**
37
+ */
38
+ public function run() {
39
+
40
+ if ( $this->getIsOption( 'enable_audit_context_plugins', 'Y' ) ) {
41
+ add_action( 'deactivated_plugin', array( $this, 'auditDeactivatedPlugin' ) );
42
+ add_action( 'activated_plugin', array( $this, 'auditActivatedPlugin' ) );
43
+ }
44
+
45
+ }
46
+
47
+ /**
48
+ * @param string $sPlugin
49
+ * @return bool
50
+ */
51
+ public function auditActivatedPlugin( $sPlugin ) {
52
+
53
+ if ( empty( $sPlugin ) ) {
54
+ return false;
55
+ }
56
+
57
+ $oAuditTrail = $this->getAuditTrailEntries();
58
+ $oAuditTrail->add(
59
+ 'plugins',
60
+ 'plugin_activated',
61
+ 1,
62
+ sprintf( _wpsf__( 'Plugin "%s" was activated.' ), $sPlugin )
63
+ );
64
+ }
65
+
66
+ /**
67
+ * @param string $sPlugin
68
+ * @return bool
69
+ */
70
+ public function auditDeactivatedPlugin( $sPlugin ) {
71
+
72
+ if ( empty( $sPlugin ) ) {
73
+ return false;
74
+ }
75
+
76
+ $oAuditTrail = $this->getAuditTrailEntries();
77
+ $oAuditTrail->add(
78
+ 'plugins',
79
+ 'plugin_deactivated',
80
+ 1,
81
+ sprintf( _wpsf__( 'Plugin "%s" was deactivated.' ), $sPlugin )
82
+ );
83
+ }
84
+
85
+ /**
86
+ * @return ICWP_WPSF_AuditTrail_Entries
87
+ */
88
+ protected function getAuditTrailEntries() {
89
+ return ICWP_WPSF_AuditTrail_Entries::GetInstance();
90
+ }
91
+ }
92
+
93
+ endif;
src/icwp-processor-audit_trail_posts.php ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_AuditTrail_Posts') ):
21
+
22
+ class ICWP_WPSF_Processor_AuditTrail_Posts extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_AuditTrail
26
+ */
27
+ protected $oFeatureOptions;
28
+
29
+ /**
30
+ * @param ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions
31
+ */
32
+ public function __construct( ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions ) {
33
+ parent::__construct( $oFeatureOptions );
34
+ }
35
+
36
+ /**
37
+ */
38
+ public function run() {
39
+ if ( $this->getIsOption( 'enable_audit_context_wordpress', 'Y' ) ) {
40
+ add_action( 'deleted_post', array( $this, 'auditDeletedPost' ) );
41
+ add_action( 'transition_post_status', array( $this, 'auditPostStatus' ), 30 , 3 );
42
+ }
43
+ }
44
+
45
+ /**
46
+ * @param string $nPostId
47
+ * @return bool
48
+ */
49
+ public function auditDeletedPost( $nPostId ) {
50
+
51
+ $oPost = get_post( $nPostId );
52
+ if ( ! ( $oPost instanceof WP_Post ) || ( $this->getIsIgnoredPostType( $oPost ) ) ) {
53
+ return;
54
+ }
55
+
56
+ $oAuditTrail = $this->getAuditTrailEntries();
57
+ $oAuditTrail->add(
58
+ 'posts',
59
+ 'post_deleted',
60
+ 2,
61
+ sprintf( _wpsf__( 'WordPress Post entitled "%s" was permanently deleted from trash.' ), $oPost->post_title )
62
+ );
63
+
64
+ }
65
+
66
+
67
+ /**
68
+ * @param string $sNewStatus
69
+ * @param string $sOldStatus
70
+ * @param WP_Post $oPost
71
+ * @return bool
72
+ */
73
+ public function auditPostStatus( $sNewStatus, $sOldStatus, $oPost ) {
74
+
75
+ if ( ! ( $oPost instanceof WP_Post ) || ( $this->getIsIgnoredPostType( $oPost ) ) || in_array( $sNewStatus, array( 'auto-draft', 'inherit' ) ) ) {
76
+ return;
77
+ }
78
+
79
+ if ( $sNewStatus == 'trash' ) {
80
+ $sEvent = 'post_trashed';
81
+ $sHumanEvent = _wpsf__( 'moved to trash' );
82
+ }
83
+ else if ( $sOldStatus == 'trash' && $sNewStatus != 'trash' ) {
84
+ $sEvent = 'post_recovered';
85
+ $sHumanEvent = _wpsf__( 'recovered from trash' );
86
+ }
87
+ else if ( in_array( $sNewStatus, array( 'publish', 'private' ) ) ) {
88
+ $sEvent = 'post_published';
89
+ $sHumanEvent = _wpsf__( 'published' );
90
+ }
91
+ else if ( in_array( $sOldStatus, array( 'publish', 'private' ) ) && $sNewStatus == 'draft' ) {
92
+ $sEvent = 'post_unpublished';
93
+ $sHumanEvent = _wpsf__( 'unpublished' );
94
+ }
95
+ else {
96
+ $sEvent = 'post_updated';
97
+ $sHumanEvent = _wpsf__( 'updated' );
98
+ }
99
+
100
+ $oAuditTrail = $this->getAuditTrailEntries();
101
+ $oAuditTrail->add(
102
+ 'posts',
103
+ $sEvent,
104
+ 1,
105
+ sprintf( _wpsf__( 'Post entitled "%s" was %s.' ), $oPost->post_title, $sHumanEvent )
106
+ );
107
+
108
+ }
109
+
110
+ /**
111
+ * @param WP_Post $oPost
112
+ * @return bool
113
+ */
114
+ protected function getIsIgnoredPostType( $oPost ) {
115
+ return
116
+ ( $oPost->post_status == 'auto-draft' )
117
+ ||
118
+ in_array(
119
+ $oPost->post_type,
120
+ array(
121
+ 'revision',
122
+ 'nav_menu_item',
123
+ 'attachment'
124
+ )
125
+ );
126
+ }
127
+
128
+ /**
129
+ * @return ICWP_WPSF_AuditTrail_Entries
130
+ */
131
+ protected function getAuditTrailEntries() {
132
+ return ICWP_WPSF_AuditTrail_Entries::GetInstance();
133
+ }
134
+ }
135
+
136
+ endif;
src/icwp-processor-audit_trail_themes.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_AuditTrail_Themes') ):
21
+
22
+ class ICWP_WPSF_Processor_AuditTrail_Themes extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_AuditTrail
26
+ */
27
+ protected $oFeatureOptions;
28
+
29
+ /**
30
+ * @param ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions
31
+ */
32
+ public function __construct( ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions ) {
33
+ parent::__construct( $oFeatureOptions );
34
+ }
35
+
36
+ /**
37
+ */
38
+ public function run() {
39
+
40
+ if ( $this->getIsOption( 'enable_audit_context_themes', 'Y' ) ) {
41
+ add_action( 'switch_theme', array( $this, 'auditSwitchTheme' ) );
42
+ // add_action( 'upgrader_process_complete', array( $this, 'auditInstalledTheme' ) );
43
+ }
44
+
45
+ }
46
+
47
+ /**
48
+ * @param string $sThemeName
49
+ * @return bool
50
+ */
51
+ public function auditSwitchTheme( $sThemeName ) {
52
+
53
+ if ( empty( $sThemeName ) ) {
54
+ return false;
55
+ }
56
+
57
+ $oAuditTrail = $this->getAuditTrailEntries();
58
+ $oAuditTrail->add(
59
+ 'themes',
60
+ 'theme_activated',
61
+ 1,
62
+ sprintf( _wpsf__( 'Theme "%s" was activated.' ), $sThemeName )
63
+ );
64
+ }
65
+
66
+ /**
67
+ * @return ICWP_WPSF_AuditTrail_Entries
68
+ */
69
+ protected function getAuditTrailEntries() {
70
+ return ICWP_WPSF_AuditTrail_Entries::GetInstance();
71
+ }
72
+ }
73
+
74
+ endif;
src/icwp-processor-audit_trail_users.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_AuditTrail_Users') ):
21
+
22
+ class ICWP_WPSF_Processor_AuditTrail_Users extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_AuditTrail
26
+ */
27
+ protected $oFeatureOptions;
28
+
29
+ /**
30
+ * @param ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions
31
+ */
32
+ public function __construct( ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions ) {
33
+ parent::__construct( $oFeatureOptions );
34
+ }
35
+
36
+ /**
37
+ */
38
+ public function run() {
39
+
40
+ if ( $this->getIsOption( 'enable_audit_context_users', 'Y' ) ) {
41
+ add_action( 'wp_login_failed', array( $this, 'auditUserLoginFail' ) );
42
+ add_action( 'wp_login', array( $this, 'auditUserLoginSuccess' ) );
43
+ add_action( 'user_register', array( $this, 'auditNewUserRegistered' ) );
44
+ add_action( 'delete_user', array( $this, 'auditDeleteUser' ), 30, 2 );
45
+ }
46
+
47
+ }
48
+
49
+ /**
50
+ * @param string $sUsername
51
+ * @return bool
52
+ */
53
+ public function auditUserLoginSuccess( $sUsername ) {
54
+
55
+ if ( empty( $sUsername ) ) {
56
+ return false;
57
+ }
58
+
59
+ $oAuditTrail = $this->getAuditTrailEntries();
60
+ $oAuditTrail->add(
61
+ 'users',
62
+ 'login_success',
63
+ 1,
64
+ sprintf( _wpsf__( 'Attempted user login by "%s" was successful.' ), $sUsername )
65
+ );
66
+ }
67
+
68
+ /**
69
+ * @param string $sUsername
70
+ * @return bool
71
+ */
72
+ public function auditUserLoginFail( $sUsername ) {
73
+
74
+ if ( empty( $sUsername ) ) {
75
+ return false;
76
+ }
77
+
78
+ $oAuditTrail = $this->getAuditTrailEntries();
79
+ $oAuditTrail->add(
80
+ 'users',
81
+ 'login_failure',
82
+ 2,
83
+ sprintf( _wpsf__( 'Attempted user login by "%s" was failed.' ), $sUsername )
84
+ );
85
+ }
86
+
87
+ /**
88
+ * @param int $nUserId
89
+ * @return bool
90
+ */
91
+ public function auditNewUserRegistered( $nUserId ) {
92
+ if ( empty( $nUserId ) ) {
93
+ return false;
94
+ }
95
+ $oWp = $this->loadWpFunctionsProcessor();
96
+ $oNewUser = $oWp->getUserById( $nUserId );
97
+
98
+ $oAuditTrail = $this->getAuditTrailEntries();
99
+ $oAuditTrail->add(
100
+ 'users',
101
+ 'user_registered',
102
+ 1,
103
+ _wpsf__( 'New WordPress user registered.').' '
104
+ .sprintf(
105
+ _wpsf__( 'New username is "%s" with email address "%s".' ),
106
+ empty( $oNewUser ) ? 'unknown' : $oNewUser->get( 'user_login' ),
107
+ empty( $oNewUser ) ? 'unknown' : $oNewUser->get( 'user_email' )
108
+ )
109
+ );
110
+ }
111
+
112
+ /**
113
+ * @param int $nUserId
114
+ * @param int $nReassigned
115
+ * @return bool
116
+ */
117
+ public function auditDeleteUser( $nUserId, $nReassigned ) {
118
+ if ( empty( $nUserId ) ) {
119
+ return false;
120
+ }
121
+ $oWp = $this->loadWpFunctionsProcessor();
122
+ $oDeletedUser = $oWp->getUserById( $nUserId );
123
+ $oReassignedUser = empty( $nReassigned ) ? null : $oWp->getUserById( $nReassigned );
124
+
125
+ // Build the audit message
126
+ $sAuditMessage =
127
+ _wpsf__( 'WordPress user deleted.')
128
+ .' '.sprintf(
129
+ _wpsf__( 'Username was "%s" with email address "%s".' ),
130
+ empty( $oDeletedUser ) ? 'unknown' : $oDeletedUser->get( 'user_login' ),
131
+ empty( $oDeletedUser ) ? 'unknown' : $oDeletedUser->get( 'user_email' )
132
+ ).' ';
133
+ if ( empty( $oReassignedUser ) ) {
134
+ $sAuditMessage .= _wpsf__( 'Their posts were not reassigned to another user.' );
135
+ }
136
+ else {
137
+ $sAuditMessage .= sprintf(
138
+ _wpsf__( 'Their posts were reassigned to user "%s".' ),
139
+ $oReassignedUser->get( 'user_login' )
140
+ );
141
+ }
142
+
143
+ $oAuditTrail = $this->getAuditTrailEntries();
144
+ $oAuditTrail->add(
145
+ 'users',
146
+ 'user_deleted',
147
+ 2,
148
+ $sAuditMessage
149
+ );
150
+ }
151
+
152
+ /**
153
+ * @return ICWP_WPSF_AuditTrail_Entries
154
+ */
155
+ protected function getAuditTrailEntries() {
156
+ return ICWP_WPSF_AuditTrail_Entries::GetInstance();
157
+ }
158
+ }
159
+
160
+ endif;
src/icwp-processor-audit_trail_wordpress.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_AuditTrail_Wordpress') ):
21
+
22
+ class ICWP_WPSF_Processor_AuditTrail_Wordpress extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_AuditTrail
26
+ */
27
+ protected $oFeatureOptions;
28
+
29
+ /**
30
+ * @param ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions
31
+ */
32
+ public function __construct( ICWP_WPSF_FeatureHandler_AuditTrail $oFeatureOptions ) {
33
+ parent::__construct( $oFeatureOptions );
34
+ }
35
+
36
+ /**
37
+ */
38
+ public function run() {
39
+ if ( $this->getIsOption( 'enable_audit_context_wordpress', 'Y' ) ) {
40
+ add_action( '_core_updated_successfully', array( $this, 'auditCoreUpdated' ) );
41
+ add_action( 'update_option_permalink_structure', array( $this, 'auditPermalinkStructure' ), 10, 2 );
42
+ }
43
+ }
44
+
45
+ /**
46
+ * @param string $sNewCoreVersion
47
+ * @return bool
48
+ */
49
+ public function auditCoreUpdated( $sNewCoreVersion ) {
50
+ global $wp_version;
51
+
52
+ $oAuditTrail = $this->getAuditTrailEntries();
53
+ $oAuditTrail->add(
54
+ 'wordpress',
55
+ 'core_updated',
56
+ 1,
57
+ sprintf( _wpsf__( 'WordPress Core was updated from "v%s" to "v%s".' ), $wp_version, $sNewCoreVersion )
58
+ );
59
+ }
60
+
61
+ /**
62
+ * @param string $sOld
63
+ * @param string $sNew
64
+ * @return bool
65
+ */
66
+ public function auditPermalinkStructure( $sOld, $sNew ) {
67
+ $oAuditTrail = $this->getAuditTrailEntries();
68
+ $oAuditTrail->add(
69
+ 'wordpress',
70
+ 'permalinks_structure',
71
+ 1,
72
+ sprintf( _wpsf__( 'WordPress Permalinks Structure was updated from "%s" to "%s".' ), $sOld, $sNew )
73
+ );
74
+ }
75
+
76
+ /**
77
+ * @return ICWP_WPSF_AuditTrail_Entries
78
+ */
79
+ protected function getAuditTrailEntries() {
80
+ return ICWP_WPSF_AuditTrail_Entries::GetInstance();
81
+ }
82
+ }
83
+
84
+ endif;
src/icwp-processor-autoupdates.php CHANGED
@@ -15,46 +15,49 @@
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
- require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
  if ( !class_exists('ICWP_AutoupdatesProcessor_V5') ):
21
 
22
- class ICWP_AutoupdatesProcessor_V5 extends ICWP_BaseProcessor_V3 {
23
 
24
  const FilterPriority = 1001;
25
 
26
- protected $sPluginFile;
27
-
28
  /**
29
  * @var boolean
30
  */
31
- protected $m_fDoForceRunAutoupdates = false;
32
 
33
  /**
34
  * @param ICWP_WPSF_FeatureHandler_Autoupdates $oFeatureOptions
35
  */
36
  public function __construct( ICWP_WPSF_FeatureHandler_Autoupdates $oFeatureOptions ) {
37
  parent::__construct( $oFeatureOptions );
38
- $this->sPluginFile = $this->oFeatureOptions->getPluginBaseFile();
39
  }
40
 
41
  /**
42
  * @param boolean $infDoForceRun
43
  */
44
  public function setForceRunAutoupdates( $infDoForceRun ) {
45
- $this->m_fDoForceRunAutoupdates = $infDoForceRun;
46
  }
47
-
48
  /**
 
49
  */
50
  public function getForceRunAutoupdates() {
51
- return apply_filters( 'icwp_force_autoupdate', $this->m_fDoForceRunAutoupdates );
52
  }
53
 
54
  /**
55
  */
56
  public function run() {
57
 
 
 
 
 
 
58
  // When we force run we only want our filters.
59
  if ( $this->getForceRunAutoupdates() ) {
60
  $aFilters = array(
@@ -195,7 +198,7 @@ class ICWP_AutoupdatesProcessor_V5 extends ICWP_BaseProcessor_V3 {
195
  return $infUpdate;
196
  }
197
 
198
- if ( $sItemFile === $this->sPluginFile ) {
199
  if ( $this->getIsOption('autoupdate_plugin_self', 'Y') ) {
200
  $this->doStatIncrement( 'autoupdates.plugins.self' );
201
  return true;
@@ -214,7 +217,7 @@ class ICWP_AutoupdatesProcessor_V5 extends ICWP_BaseProcessor_V3 {
214
 
215
  return $infUpdate;
216
  }
217
-
218
  /**
219
  * This is a filter method designed to say whether WordPress theme upgrades should be permitted,
220
  * based on the plugin settings.
@@ -243,35 +246,36 @@ class ICWP_AutoupdatesProcessor_V5 extends ICWP_BaseProcessor_V3 {
243
  }
244
 
245
  $aAutoupdateThemeFiles = apply_filters( 'icwp_wpsf_autoupdate_themes', array() );
246
-
247
  if ( !empty( $aAutoupdateThemeFiles )
248
  && is_array($aAutoupdateThemeFiles)
249
  && in_array( $sItemFile, $aAutoupdateThemeFiles ) ) {
250
 
251
  return true;
252
  }
253
-
254
  return $infUpdate;
255
  }
256
-
257
  /**
258
  * This is a filter method designed to say whether WordPress automatic upgrades should be permitted
259
  * if a version control system is detected.
260
- *
261
- * @param boolean $infUpdate
 
262
  * @return boolean
263
  */
264
  public function disable_for_vcs( $checkout, $context ) {
265
  return false;
266
  }
267
-
268
  /**
269
  * A filter on whether or not a notification email is send after core upgrades are attempted.
270
  *
271
- * @param boolean $infSendEmail
272
  * @return boolean
273
  */
274
- public function autoupdate_send_email( $infSendEmail ) {
275
  return $this->getIsOption( 'enable_upgrade_notification_email', 'Y' );
276
  }
277
 
@@ -292,6 +296,6 @@ class ICWP_AutoupdatesProcessor_V5 extends ICWP_BaseProcessor_V3 {
292
 
293
  endif;
294
 
295
- if ( !class_exists('ICWP_WPSF_AutoupdatesProcessor') ):
296
- class ICWP_WPSF_AutoupdatesProcessor extends ICWP_AutoupdatesProcessor_V5 { }
297
  endif;
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
 
20
  if ( !class_exists('ICWP_AutoupdatesProcessor_V5') ):
21
 
22
+ class ICWP_AutoupdatesProcessor_V5 extends ICWP_WPSF_Processor_Base {
23
 
24
  const FilterPriority = 1001;
25
 
 
 
26
  /**
27
  * @var boolean
28
  */
29
+ protected $fDoForceRunAutoupdates = false;
30
 
31
  /**
32
  * @param ICWP_WPSF_FeatureHandler_Autoupdates $oFeatureOptions
33
  */
34
  public function __construct( ICWP_WPSF_FeatureHandler_Autoupdates $oFeatureOptions ) {
35
  parent::__construct( $oFeatureOptions );
 
36
  }
37
 
38
  /**
39
  * @param boolean $infDoForceRun
40
  */
41
  public function setForceRunAutoupdates( $infDoForceRun ) {
42
+ $this->fDoForceRunAutoupdates = $infDoForceRun;
43
  }
44
+
45
  /**
46
+ * @return boolean
47
  */
48
  public function getForceRunAutoupdates() {
49
+ return apply_filters( $this->getFeatureOptions()->doPluginPrefix( 'force_autoupdate' ), $this->fDoForceRunAutoupdates );
50
  }
51
 
52
  /**
53
  */
54
  public function run() {
55
 
56
+ $oDp = $this->loadDataProcessor();
57
+ if ( $oDp->FetchGet( 'forcerun' ) == 1 ) {
58
+ $this->setForceRunAutoupdates( true );
59
+ }
60
+
61
  // When we force run we only want our filters.
62
  if ( $this->getForceRunAutoupdates() ) {
63
  $aFilters = array(
198
  return $infUpdate;
199
  }
200
 
201
+ if ( $sItemFile === $this->getFeatureOptions()->getPluginBaseFile() ) {
202
  if ( $this->getIsOption('autoupdate_plugin_self', 'Y') ) {
203
  $this->doStatIncrement( 'autoupdates.plugins.self' );
204
  return true;
217
 
218
  return $infUpdate;
219
  }
220
+
221
  /**
222
  * This is a filter method designed to say whether WordPress theme upgrades should be permitted,
223
  * based on the plugin settings.
246
  }
247
 
248
  $aAutoupdateThemeFiles = apply_filters( 'icwp_wpsf_autoupdate_themes', array() );
249
+
250
  if ( !empty( $aAutoupdateThemeFiles )
251
  && is_array($aAutoupdateThemeFiles)
252
  && in_array( $sItemFile, $aAutoupdateThemeFiles ) ) {
253
 
254
  return true;
255
  }
256
+
257
  return $infUpdate;
258
  }
259
+
260
  /**
261
  * This is a filter method designed to say whether WordPress automatic upgrades should be permitted
262
  * if a version control system is detected.
263
+ *
264
+ * @param $checkout
265
+ * @param $context
266
  * @return boolean
267
  */
268
  public function disable_for_vcs( $checkout, $context ) {
269
  return false;
270
  }
271
+
272
  /**
273
  * A filter on whether or not a notification email is send after core upgrades are attempted.
274
  *
275
+ * @param boolean $fSendEmail
276
  * @return boolean
277
  */
278
+ public function autoupdate_send_email( $fSendEmail ) {
279
  return $this->getIsOption( 'enable_upgrade_notification_email', 'Y' );
280
  }
281
 
296
 
297
  endif;
298
 
299
+ if ( !class_exists('ICWP_WPSF_Processor_Autoupdates') ):
300
+ class ICWP_WPSF_Processor_Autoupdates extends ICWP_AutoupdatesProcessor_V5 { }
301
  endif;
src/icwp-processor-base.php ADDED
@@ -0,0 +1,333 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ *
17
+ */
18
+
19
+ if ( !class_exists('ICWP_BaseProcessor_V3') ):
20
+
21
+ class ICWP_BaseProcessor_V3 extends ICWP_WPSF_Foundation {
22
+
23
+ const PcreDelimiter = '/';
24
+ const LOG_MESSAGE_LEVEL_INFO = 0;
25
+ const LOG_MESSAGE_LEVEL_WARNING = 1;
26
+ const LOG_MESSAGE_LEVEL_CRITICAL = 2;
27
+
28
+ const LOG_CATEGORY_DEFAULT = 0;
29
+ const LOG_CATEGORY_FIREWALL = 1;
30
+ const LOG_CATEGORY_LOGINPROTECT = 2;
31
+
32
+ /**
33
+ * @var array
34
+ */
35
+ protected $m_aLog;
36
+ /**
37
+ * @var array
38
+ */
39
+ protected $m_aLogMessages;
40
+
41
+ /**
42
+ * @var long
43
+ */
44
+ protected static $nRequestIp;
45
+ /**
46
+ * @var long
47
+ */
48
+ protected static $nRequestPostId;
49
+ /**
50
+ * @var integer
51
+ */
52
+ protected static $nRequestTimestamp;
53
+
54
+ /**
55
+ * @var ICWP_WPSF_FeatureHandler_Base
56
+ */
57
+ protected $oFeatureOptions;
58
+
59
+ public function __construct( ICWP_WPSF_FeatureHandler_Base $oFeatureOptions ) {
60
+ $this->oFeatureOptions = $oFeatureOptions;
61
+ $this->reset();
62
+ }
63
+
64
+ /**
65
+ * Resets the object values to be re-used anew
66
+ */
67
+ public function reset() {
68
+ $oDp = $this->loadDataProcessor();
69
+ if ( !isset( self::$nRequestIp ) ) {
70
+ self::$nRequestIp = $oDp->GetVisitorIpAddress();
71
+ }
72
+ if ( !isset( self::$nRequestTimestamp ) ) {
73
+ self::$nRequestTimestamp = $oDp->GetRequestTime();
74
+ }
75
+ $this->resetLog();
76
+ }
77
+
78
+ /**
79
+ * Override to set what this processor does when it's "run"
80
+ */
81
+ public function run() { }
82
+
83
+ /**
84
+ * @param $sOptionKey
85
+ * @param bool $mDefault
86
+ * @return bool
87
+ */
88
+ public function getOption( $sOptionKey, $mDefault = false ) {
89
+ return $this->getFeatureOptions()->getOpt( $sOptionKey, $mDefault );
90
+ }
91
+
92
+ /**
93
+ * @param $sKey
94
+ * @param mixed $mValueToTest
95
+ * @param boolean $fStrict
96
+ * @return bool
97
+ */
98
+ public function getIsOption( $sKey, $mValueToTest, $fStrict = false ) {
99
+ $mOptionValue = $this->getOption( $sKey );
100
+ return $fStrict? $mOptionValue === $mValueToTest : $mOptionValue == $mValueToTest;
101
+ }
102
+
103
+ /**
104
+ * @return bool|long
105
+ */
106
+ public function getRequestPostId() {
107
+ if ( !isset( self::$nRequestPostId ) ) {
108
+ global $post;
109
+ if ( empty( $post ) ) {
110
+ return false;
111
+ }
112
+ self::$nRequestPostId = $post->ID;
113
+ }
114
+ return self::$nRequestPostId;
115
+ }
116
+
117
+ /**
118
+ * Resets the log
119
+ */
120
+ public function resetLog() {
121
+ $this->m_aLogMessages = array();
122
+ }
123
+
124
+ /**
125
+ * @return bool
126
+ */
127
+ public function getIsLogging() {
128
+ return false;
129
+ }
130
+
131
+ /**
132
+ * Should return false when logging is disabled.
133
+ *
134
+ * @return false|array - false when logging is disabled, array with log data otherwise
135
+ * @see ICWP_WPSF_Processor_Base::getLogData()
136
+ */
137
+ public function flushLogData() {
138
+ if ( !$this->getIsLogging() ) {
139
+ return false;
140
+ }
141
+ return false;
142
+ }
143
+
144
+ /**
145
+ * Builds and returns the full log.
146
+ *
147
+ * @return array (associative)
148
+ */
149
+ public function getLogData() {
150
+
151
+ if ( $this->getIsLogging() ) {
152
+ $this->m_aLog = array( 'messages' => serialize( $this->m_aLogMessages ) );
153
+ }
154
+ else {
155
+ $this->m_aLog = false;
156
+ }
157
+
158
+ return $this->m_aLog;
159
+ }
160
+
161
+ /**
162
+ * @return array
163
+ */
164
+ public function getLogMessages() {
165
+ if ( !is_array( $this->m_aLogMessages ) ) {
166
+ $this->m_aLogMessages = array();
167
+ }
168
+ return $this->m_aLogMessages;
169
+ }
170
+
171
+ /**
172
+ * @param string $sLogMessage
173
+ * @param integer $sMessageType
174
+ */
175
+ public function writeLog( $sLogMessage = '', $sMessageType = self::LOG_MESSAGE_LEVEL_INFO ) {
176
+ if ( !is_array( $this->m_aLogMessages ) ) {
177
+ $this->resetLog();
178
+ }
179
+ $this->m_aLogMessages[] = array( $sMessageType, $sLogMessage );
180
+ }
181
+ /**
182
+ * @param string $insLogMessage
183
+ */
184
+ public function logInfo( $insLogMessage ) {
185
+ $this->writeLog( $insLogMessage, self::LOG_MESSAGE_LEVEL_INFO );
186
+ }
187
+ /**
188
+ * @param string $insLogMessage
189
+ */
190
+ public function logWarning( $insLogMessage ) {
191
+ $this->writeLog( $insLogMessage, self::LOG_MESSAGE_LEVEL_WARNING );
192
+ }
193
+ /**
194
+ * @param string $insLogMessage
195
+ */
196
+ public function logCritical( $insLogMessage ) {
197
+ $this->writeLog( $insLogMessage, self::LOG_MESSAGE_LEVEL_CRITICAL );
198
+ }
199
+
200
+ /**
201
+ * @param array $inaIpList
202
+ * @param integer $innIpAddress
203
+ * @param string $outsLabel
204
+ * @return boolean
205
+ */
206
+ public function isIpOnlist( $inaIpList, $innIpAddress = 0, &$outsLabel = '' ) {
207
+
208
+ if ( empty( $innIpAddress ) || !isset( $inaIpList['ips'] ) ) {
209
+ return false;
210
+ }
211
+
212
+ $outsLabel = '';
213
+ foreach( $inaIpList['ips'] as $mWhitelistAddress ) {
214
+
215
+ $aIps = $this->parseIpAddress( $mWhitelistAddress );
216
+ if ( count( $aIps ) === 1 ) { //not a range
217
+ if ( $innIpAddress == $aIps[0] ) {
218
+ $outsLabel = $inaIpList['meta'][ md5( $mWhitelistAddress ) ];
219
+ return true;
220
+ }
221
+ }
222
+ else if ( count( $aIps ) == 2 ) {
223
+ if ( $aIps[0] <= $innIpAddress && $innIpAddress <= $aIps[1] ) {
224
+ $outsLabel = $inaIpList['meta'][ md5( $mWhitelistAddress ) ];
225
+ return true;
226
+ }
227
+ }
228
+ }
229
+ return false;
230
+ }
231
+
232
+ /**
233
+ * @param string $sIpAddress - an IP or IP address range in LONG format.
234
+ * @return array - with 1 ip address, or 2 addresses if it is a range.
235
+ */
236
+ protected function parseIpAddress( $sIpAddress ) {
237
+
238
+ $aIps = array();
239
+
240
+ if ( empty($sIpAddress) ) {
241
+ return $aIps;
242
+ }
243
+
244
+ // offset=1 in the case that it's a range and the first number is negative on 32-bit systems
245
+ $mPos = strpos( $sIpAddress, '-', 1 );
246
+
247
+ if ( $mPos === false ) { //plain IP address
248
+ $aIps[] = $sIpAddress;
249
+ }
250
+ else {
251
+ //we remove the first character in case this is '-'
252
+ $aParts = array( substr( $sIpAddress, 0, 1 ), substr( $sIpAddress, 1 ) );
253
+ list( $sStart, $sEnd ) = explode( '-', $aParts[1], 2 );
254
+ $aIps[] = $aParts[0].$sStart;
255
+ $aIps[] = $sEnd;
256
+ }
257
+ return $aIps;
258
+ }
259
+
260
+ /**
261
+ * @return ICWP_WPSF_Processor_Email
262
+ */
263
+ public function getEmailProcessor() {
264
+ return $this->getFeatureOptions()->getEmailProcessor();
265
+ }
266
+
267
+ /**
268
+ * @return ICWP_WPSF_Processor_Logging
269
+ */
270
+ public function getLoggingProcessor() {
271
+ return $this->getFeatureOptions()->getLoggingProcessor();
272
+ }
273
+
274
+ /**
275
+ * Checks the $aData contains valid key values as laid out in $inaChecks
276
+ *
277
+ * @param array $aData
278
+ * @param array $inaChecks
279
+ * @return boolean
280
+ */
281
+ protected function validateParameters( $aData, $inaChecks ) {
282
+
283
+ if ( !is_array( $aData ) ) {
284
+ return false;
285
+ }
286
+
287
+ foreach( $inaChecks as $sCheck ) {
288
+ if ( !array_key_exists( $sCheck, $aData ) || empty( $aData[ $sCheck ] ) ) {
289
+ return false;
290
+ }
291
+ }
292
+ return true;
293
+ }
294
+
295
+ /**
296
+ * @param $sStatKey
297
+ */
298
+ protected function doStatIncrement( $sStatKey ) {
299
+ $this->getFeatureOptions()->doStatIncrement( $sStatKey );
300
+ }
301
+
302
+ /**
303
+ * @return ICWP_WPSF_FeatureHandler_Base
304
+ */
305
+ protected function getFeatureOptions() {
306
+ return $this->oFeatureOptions;
307
+ }
308
+
309
+ /**
310
+ * Provides the basic HTML template for printing a WordPress Admin Notices
311
+ *
312
+ * @param $sNotice - The message to be displayed.
313
+ * @param $sMessageClass - either error or updated
314
+ * @param $infPrint - if true, will echo. false will return the string
315
+ * @return boolean|string
316
+ */
317
+ protected function getAdminNoticeHtml( $sNotice = '', $sMessageClass = 'updated', $infPrint = false ) {
318
+ $sWrapper = '<div class="%s icwp-admin-notice">%s</div>';
319
+ $sFullNotice = sprintf( $sWrapper, $sMessageClass, $sNotice );
320
+ if ( $infPrint ) {
321
+ echo $sFullNotice;
322
+ return true;
323
+ } else {
324
+ return $sFullNotice;
325
+ }
326
+ }
327
+ }
328
+
329
+ endif;
330
+
331
+ if ( !class_exists('ICWP_WPSF_Processor_Base') ):
332
+ class ICWP_WPSF_Processor_Base extends ICWP_BaseProcessor_V3 { }
333
+ endif;
src/{icwp-basedb-processor.php → icwp-processor-basedb.php} RENAMED
@@ -16,16 +16,12 @@
16
  *
17
  */
18
 
19
- require_once( dirname(__FILE__).'/icwp-base-processor.php' );
20
 
21
- if ( !class_exists('ICWP_BaseDbProcessor_WPSF') ):
22
 
23
- class ICWP_BaseDbProcessor_WPSF extends ICWP_WPSF_BaseProcessor {
24
 
25
- const DB_TABLE_PREFIX = 'icwp_';
26
-
27
- /**
28
- */
29
  const CleanupCronActionHook = 'icwp_wpsf_cron_cleanupactionhook';
30
 
31
  /**
@@ -43,33 +39,74 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_WPSF_BaseProcessor {
43
  * @var array
44
  */
45
  protected $m_aDataToWrite;
 
 
 
 
 
46
 
47
  public function __construct( ICWP_WPSF_FeatureHandler_Base $oFeatureOptions, $sTableName = null ) {
48
  parent::__construct( $oFeatureOptions );
49
  $this->setTableName( $sTableName );
50
  $this->createCleanupCron();
 
51
  }
52
 
53
  /**
54
  * Override to set what this processor does when it's "run"
55
  */
56
- public function run() {
57
- if ( $this->getTableExists() ) {
58
- $sFullHookName = $this->oFeatureOptions->doPluginPrefix( self::CleanupCronActionHook, '_' );
59
- add_action( $sFullHookName, array( $this, 'cleanupDatabase' ) );
 
 
 
60
  }
61
  }
62
 
63
  /**
64
  * Loads our WPDB object if required.
 
 
65
  */
66
  protected function loadWpdb() {
67
  if ( is_null( $this->oWpdb ) ) {
68
- global $wpdb;
69
- $this->oWpdb = $wpdb;
70
  }
71
  return $this->oWpdb;
72
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  /**
75
  * @param array $inaLogData
@@ -104,7 +141,7 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_WPSF_BaseProcessor {
104
  * @return boolean - whether the write to the DB was successful.
105
  */
106
  public function commitData() {
107
- if ( empty( $this->m_aDataToWrite ) ) {
108
  return;
109
  }
110
  $fSuccess = true;
@@ -121,7 +158,6 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_WPSF_BaseProcessor {
121
  }
122
 
123
  /**
124
- *
125
  */
126
  protected function flushData() {
127
  $this->m_aDataToWrite = null;
@@ -135,33 +171,60 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_WPSF_BaseProcessor {
135
  $oDb = $this->loadWpdb();
136
  return $oDb->insert( $this->getTableName(), $aData );
137
  }
138
-
139
- public function selectAllFromTable( $innFormat = ARRAY_A ) {
 
 
 
 
140
  $oDb = $this->loadWpdb();
141
  $sQuery = sprintf( "SELECT * FROM `%s` WHERE `deleted_at` = '0'", $this->getTableName() );
142
- return $oDb->get_results( $sQuery, $innFormat );
143
  }
144
-
145
- public function selectCustomFromTable( $sQuery ) {
 
 
 
 
 
146
  $oDb = $this->loadWpdb();
147
- return $oDb->get_results( $sQuery, ARRAY_A );
148
  }
149
-
150
- public function selectRowFromTable( $sQuery ) {
 
 
 
 
 
151
  $oDb = $this->loadWpdb();
152
- return $oDb->get_row( $sQuery, ARRAY_A );
153
  }
154
-
 
 
 
 
 
155
  public function updateRowsFromTable( $aData, $aWhere ) {
156
  $oDb = $this->loadWpdb();
157
  return $oDb->update( $this->getTableName(), $aData, $aWhere );
158
  }
159
-
 
 
 
 
160
  public function deleteRowsFromTable( $aWhere ) {
161
  $oDb = $this->loadWpdb();
162
  return $oDb->delete( $this->getTableName(), $aWhere );
163
  }
164
-
 
 
 
 
165
  protected function deleteAllRowsOlderThan( $nTime ) {
166
  $sQuery = "
167
  DELETE from `%s`
@@ -173,12 +236,13 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_WPSF_BaseProcessor {
173
  $this->getTableName(),
174
  $nTime
175
  );
176
- $this->doSql( $sQuery );
177
  }
178
 
179
- public function createTable() {
180
- //Override this function to create the Table you want.
181
- }
 
182
 
183
  /**
184
  * Will remove all data from this table (to delete the table see dropTable)
@@ -207,24 +271,18 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_WPSF_BaseProcessor {
207
  /**
208
  * Given any SQL query, will perform it using the WordPress database object.
209
  *
210
- * @param string $insSql
 
211
  */
212
- public function doSql( $insSql ) {
213
  $oDb = $this->loadWpdb();
214
- $fResult = $oDb->query( $insSql );
215
- return $fResult;
216
- }
217
-
218
- private function setTableName( $sTableName = null ) {
219
- $oDb = $this->loadWpdb();
220
- $sTableString =
221
- $oDb->prefix
222
- . self::DB_TABLE_PREFIX
223
- . ( is_null( $sTableName ) ? $this->oFeatureOptions->getFeatureSlug() : $sTableName );
224
- $this->sFullTableName = esc_sql( $sTableString );
225
- return $this->sFullTableName;
226
  }
227
 
 
 
 
228
  protected function getTableName() {
229
  if ( empty( $this->sFullTableName ) ) {
230
  return $this->setTableName();
@@ -233,18 +291,27 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_WPSF_BaseProcessor {
233
  }
234
 
235
  /**
236
- * Override this to provide custom cleanup.
 
 
237
  */
238
- public function deleteAndCleanUp() {
239
- parent::deleteAndCleanUp();
240
- $this->dropTable();
 
 
 
 
 
 
 
241
  }
242
 
243
  /**
244
  * Will setup the cleanup cron to clean out old entries. This should be overridden per implementation.
245
  */
246
  protected function createCleanupCron() {
247
- $sFullHookName = $this->oFeatureOptions->doPluginPrefix( self::CleanupCronActionHook, '_' );
248
  if ( ! wp_next_scheduled( $sFullHookName ) && ! defined( 'WP_INSTALLING' ) ) {
249
  $nNextRun = strtotime( 'tomorrow 6am' ) - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
250
  wp_schedule_event( $nNextRun, 'daily', $sFullHookName );
@@ -258,13 +325,21 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_WPSF_BaseProcessor {
258
  * @return bool
259
  */
260
  public function getTableExists() {
 
 
 
 
 
 
261
  $oDb = $this->loadWpdb();
262
  $sQuery = "
263
  SHOW TABLES LIKE '%s'
264
  ";
265
  $sQuery = sprintf( $sQuery, $this->getTableName() );
266
  $mResult = $oDb->get_var( $sQuery );
267
- return !is_null( $mResult );
 
 
268
  }
269
  }
270
 
16
  *
17
  */
18
 
19
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
20
 
21
+ if ( !class_exists('ICWP_WPSF_BaseDbProcessor') ):
22
 
23
+ abstract class ICWP_WPSF_BaseDbProcessor extends ICWP_WPSF_Processor_Base {
24
 
 
 
 
 
25
  const CleanupCronActionHook = 'icwp_wpsf_cron_cleanupactionhook';
26
 
27
  /**
39
  * @var array
40
  */
41
  protected $m_aDataToWrite;
42
+
43
+ /**
44
+ * @var boolean
45
+ */
46
+ protected $fTableExists;
47
 
48
  public function __construct( ICWP_WPSF_FeatureHandler_Base $oFeatureOptions, $sTableName = null ) {
49
  parent::__construct( $oFeatureOptions );
50
  $this->setTableName( $sTableName );
51
  $this->createCleanupCron();
52
+ add_action( $this->getFeatureOptions()->doPluginPrefix( 'delete_plugin' ), array( $this, 'deleteDatabase' ) );
53
  }
54
 
55
  /**
56
  * Override to set what this processor does when it's "run"
57
  */
58
+ public function run() { }
59
+
60
+ /**
61
+ */
62
+ public function deleteDatabase() {
63
+ if ( apply_filters( $this->getFeatureOptions()->doPluginPrefix( 'has_permission_to_submit' ), true ) && $this->getTableExists() ) {
64
+ $this->dropTable();
65
  }
66
  }
67
 
68
  /**
69
  * Loads our WPDB object if required.
70
+ *
71
+ * @return wpdb
72
  */
73
  protected function loadWpdb() {
74
  if ( is_null( $this->oWpdb ) ) {
75
+ $this->oWpdb = $this->getWpdb();
76
+ $this->initializeTable();
77
  }
78
  return $this->oWpdb;
79
  }
80
+
81
+ /**
82
+ */
83
+ private function getWpdb() {
84
+ global $wpdb;
85
+ return $wpdb;
86
+ }
87
+
88
+ /**
89
+ * @return bool|int
90
+ */
91
+ protected function createTable() {
92
+ $sSql = $this->getCreateTableSql();
93
+ if ( !empty( $sSql ) ) {
94
+ return $this->doSql( $sSql );
95
+ }
96
+ return true;
97
+ }
98
+
99
+ /**
100
+ */
101
+ protected function initializeTable() {
102
+ if ( $this->getTableExists() ) {
103
+ $sFullHookName = $this->getFeatureOptions()->doPluginPrefix( self::CleanupCronActionHook, '_' );
104
+ add_action( $sFullHookName, array( $this, 'cleanupDatabase' ) );
105
+ }
106
+ else {
107
+ $this->createTable();
108
+ }
109
+ }
110
 
111
  /**
112
  * @param array $inaLogData
141
  * @return boolean - whether the write to the DB was successful.
142
  */
143
  public function commitData() {
144
+ if ( empty( $this->m_aDataToWrite ) || !$this->getTableExists() ) {
145
  return;
146
  }
147
  $fSuccess = true;
158
  }
159
 
160
  /**
 
161
  */
162
  protected function flushData() {
163
  $this->m_aDataToWrite = null;
171
  $oDb = $this->loadWpdb();
172
  return $oDb->insert( $this->getTableName(), $aData );
173
  }
174
+
175
+ /**
176
+ * @param $nFormat
177
+ * @return array|boolean
178
+ */
179
+ public function selectAllFromTable( $nFormat = ARRAY_A ) {
180
  $oDb = $this->loadWpdb();
181
  $sQuery = sprintf( "SELECT * FROM `%s` WHERE `deleted_at` = '0'", $this->getTableName() );
182
+ return $oDb->get_results( $sQuery, $nFormat );
183
  }
184
+
185
+ /**
186
+ * @param string $sQuery
187
+ * @param $nFormat
188
+ * @return array|boolean
189
+ */
190
+ public function selectCustomFromTable( $sQuery, $nFormat = ARRAY_A ) {
191
  $oDb = $this->loadWpdb();
192
+ return $oDb->get_results( $sQuery, $nFormat );
193
  }
194
+
195
+ /**
196
+ * @param string $sQuery
197
+ * @param $nFormat
198
+ * @return array|boolean
199
+ */
200
+ public function selectRowFromTable( $sQuery, $nFormat = ARRAY_A ) {
201
  $oDb = $this->loadWpdb();
202
+ return $oDb->get_row( $sQuery, $nFormat );
203
  }
204
+
205
+ /**
206
+ * @param array $aData - new insert data (associative array, column=>data)
207
+ * @param array $aWhere - insert where (associative array)
208
+ * @return integer|boolean (number of rows affected)
209
+ */
210
  public function updateRowsFromTable( $aData, $aWhere ) {
211
  $oDb = $this->loadWpdb();
212
  return $oDb->update( $this->getTableName(), $aData, $aWhere );
213
  }
214
+
215
+ /**
216
+ * @param array $aWhere - delete where (associative array)
217
+ * @return integer|boolean (number of rows affected)
218
+ */
219
  public function deleteRowsFromTable( $aWhere ) {
220
  $oDb = $this->loadWpdb();
221
  return $oDb->delete( $this->getTableName(), $aWhere );
222
  }
223
+
224
+ /**
225
+ * @param integer $nTime
226
+ * @return bool|int
227
+ */
228
  protected function deleteAllRowsOlderThan( $nTime ) {
229
  $sQuery = "
230
  DELETE from `%s`
236
  $this->getTableName(),
237
  $nTime
238
  );
239
+ return $this->doSql( $sQuery );
240
  }
241
 
242
+ /**
243
+ * @return string
244
+ */
245
+ abstract protected function getCreateTableSql();
246
 
247
  /**
248
  * Will remove all data from this table (to delete the table see dropTable)
271
  /**
272
  * Given any SQL query, will perform it using the WordPress database object.
273
  *
274
+ * @param string $sSqlQuery
275
+ * @return integer|boolean (number of rows affected or just true/false)
276
  */
277
+ public function doSql( $sSqlQuery ) {
278
  $oDb = $this->loadWpdb();
279
+ $mResult = $oDb->query( $sSqlQuery );
280
+ return $mResult;
 
 
 
 
 
 
 
 
 
 
281
  }
282
 
283
+ /**
284
+ * @return string
285
+ */
286
  protected function getTableName() {
287
  if ( empty( $this->sFullTableName ) ) {
288
  return $this->setTableName();
291
  }
292
 
293
  /**
294
+ * @param string $sTableName
295
+ * @return string
296
+ * @throws Exception
297
  */
298
+ private function setTableName( $sTableName = '' ) {
299
+ if ( empty( $sTableName ) ) {
300
+ throw new Exception( 'Database Table Name is EMPTY' );
301
+ }
302
+ $oDb = $this->getWpdb();
303
+ $sTableString =
304
+ $oDb->prefix
305
+ . $sTableName;
306
+ $this->sFullTableName = esc_sql( $sTableString );
307
+ return $this->sFullTableName;
308
  }
309
 
310
  /**
311
  * Will setup the cleanup cron to clean out old entries. This should be overridden per implementation.
312
  */
313
  protected function createCleanupCron() {
314
+ $sFullHookName = $this->getFeatureOptions()->doPluginPrefix( self::CleanupCronActionHook, '_' );
315
  if ( ! wp_next_scheduled( $sFullHookName ) && ! defined( 'WP_INSTALLING' ) ) {
316
  $nNextRun = strtotime( 'tomorrow 6am' ) - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
317
  wp_schedule_event( $nNextRun, 'daily', $sFullHookName );
325
  * @return bool
326
  */
327
  public function getTableExists() {
328
+
329
+ // only return true if this is true.
330
+ if ( $this->fTableExists === true ) {
331
+ return true;
332
+ }
333
+
334
  $oDb = $this->loadWpdb();
335
  $sQuery = "
336
  SHOW TABLES LIKE '%s'
337
  ";
338
  $sQuery = sprintf( $sQuery, $this->getTableName() );
339
  $mResult = $oDb->get_var( $sQuery );
340
+
341
+ $this->fTableExists = !is_null( $mResult );
342
+ return $this->fTableExists;
343
  }
344
  }
345
 
src/icwp-processor-comments_filter.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-basedb.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_CommentsFilter_V2') ):
21
+
22
+ class ICWP_WPSF_Processor_CommentsFilter_V2 extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @param ICWP_WPSF_FeatureHandler_CommentsFilter $oFeatureOptions
26
+ */
27
+ public function __construct( ICWP_WPSF_FeatureHandler_CommentsFilter $oFeatureOptions ) {
28
+ parent::__construct( $oFeatureOptions );
29
+ }
30
+
31
+ /**
32
+ */
33
+ public function run() {
34
+ parent::run();
35
+
36
+ if ( $this->getIsOption( 'enable_comments_gasp_protection', 'Y' ) ) {
37
+ require_once('icwp-processor-commentsfilter_antibotspam.php');
38
+ $oBotSpamProcessor = new ICWP_WPSF_Processor_CommentsFilter_AntiBotSpam( $this->getFeatureOptions() );
39
+ $oBotSpamProcessor->run();
40
+ }
41
+
42
+ if ( $this->getIsOption( 'enable_comments_human_spam_filter', 'Y' ) ) {
43
+ require_once( 'icwp-processor-commentsfilter_humanspam.php' );
44
+ $oHumanSpamProcessor = new ICWP_WPSF_Processor_CommentsFilter_HumanSpam( $this->getFeatureOptions() );
45
+ $oHumanSpamProcessor->run();
46
+ }
47
+
48
+ add_filter( 'pre_comment_approved', array( $this, 'doSetCommentStatus' ), 1 );
49
+ add_filter( 'pre_comment_content', array( $this, 'doInsertCommentStatusExplanation' ), 1, 1 );
50
+ add_filter( 'comment_notification_recipients', array( $this, 'doClearCommentNotificationEmail_Filter' ), 100, 1 );
51
+ }
52
+
53
+ /**
54
+ * We set the final approval status of the comments if we've set it in our scans, and empties the notification email
55
+ * in case we "trash" it (since WP sends out a notification email if it's anything but SPAM)
56
+ *
57
+ * @param $sApprovalStatus
58
+ * @return string
59
+ */
60
+ public function doSetCommentStatus( $sApprovalStatus ) {
61
+ $sStatus = apply_filters( $this->getFeatureOptions()->doPluginPrefix( 'comments_filter_status' ), '' );
62
+ return empty( $sStatus ) ? $sApprovalStatus : $sStatus;
63
+ }
64
+
65
+ /**
66
+ * @param string $sCommentContent
67
+ * @return string
68
+ */
69
+ public function doInsertCommentStatusExplanation( $sCommentContent ) {
70
+
71
+ $sExplanation = apply_filters( $this->getFeatureOptions()->doPluginPrefix( 'comments_filter_status_explanation' ), '' );
72
+
73
+ // If either spam filtering process left an explanation, we add it here
74
+ if ( !empty( $sExplanation ) ) {
75
+ $sCommentContent = $sExplanation.$sCommentContent;
76
+ }
77
+ return $sCommentContent;
78
+ }
79
+
80
+ /**
81
+ * When you set a new comment as anything but 'spam' a notification email is sent to the post author.
82
+ * We suppress this for when we mark as trash by emptying the email notifications list.
83
+ *
84
+ * @param array $aEmails
85
+ * @return array
86
+ */
87
+ public function doClearCommentNotificationEmail_Filter( $aEmails ) {
88
+ $sStatus = apply_filters( $this->getFeatureOptions()->doPluginPrefix( 'comments_filter_status' ), '' );
89
+ if ( $sStatus == 'trash' ) {
90
+ $aEmails = array();
91
+ }
92
+ return $aEmails;
93
+ }
94
+
95
+ }
96
+ endif;
97
+
98
+ if ( !class_exists('ICWP_WPSF_Processor_CommentsFilter') ):
99
+ class ICWP_WPSF_Processor_CommentsFilter extends ICWP_WPSF_Processor_CommentsFilter_V2 { }
100
+ endif;
src/{icwp-processor-commentsfilter.php → icwp-processor-commentsfilter_antibotspam.php} RENAMED
@@ -15,26 +15,11 @@
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
- require_once( dirname(__FILE__).'/icwp-basedb-processor.php' );
19
 
20
- if ( !class_exists('ICWP_CommentsFilterProcessor_V2') ):
21
 
22
- class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
23
-
24
- const TableName = 'comments_filter';
25
- const Spam_Blacklist_Source = 'https://raw.githubusercontent.com/splorp/wordpress-comment-blacklist/master/blacklist.txt';
26
-
27
- const TWODAYS = 172800;
28
-
29
- /**
30
- * @var string
31
- */
32
- static protected $sSpamBlacklistFile;
33
-
34
- /**
35
- * @var string
36
- */
37
- static protected $sModeFile_LoginThrottled;
38
 
39
  /**
40
  * The unique comment token assigned to this page
@@ -43,9 +28,9 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
43
  protected $sUniqueCommentToken;
44
  /**
45
  * The unique comment token assigned to this page
46
- * @var integer
47
  */
48
- protected $m_sUniqueFormId;
49
  /**
50
  * @var string
51
  */
@@ -55,20 +40,11 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
55
  */
56
  protected $sCommentStatusExplanation;
57
 
58
- /**
59
- * Flag as to whether Two Factor Authentication will be by-passed when sending the verification
60
- * email fails.
61
- *
62
- * @var boolean
63
- */
64
- protected $m_fAllowTwoFactorByPass;
65
-
66
  /**
67
  * @param ICWP_WPSF_FeatureHandler_CommentsFilter $oFeatureOptions
68
  */
69
  public function __construct( ICWP_WPSF_FeatureHandler_CommentsFilter $oFeatureOptions ) {
70
- parent::__construct( $oFeatureOptions, self::TableName );
71
- $this->createTable();
72
  $this->reset();
73
  }
74
 
@@ -80,7 +56,6 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
80
  $this->sUniqueCommentToken = '';
81
  $this->sCommentStatus = '';
82
  $this->sCommentStatusExplanation = '';
83
- self::$sSpamBlacklistFile = $this->oFeatureOptions->getResourcesDir().'spamblacklist.txt';
84
  }
85
 
86
  /**
@@ -89,28 +64,45 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
89
  parent::run();
90
 
91
  // Add GASP checking to the comment form.
92
- if ( $this->getIsOption('enable_comments_gasp_protection', 'Y') ) {
93
- add_action( 'comment_form', array( $this, 'printGaspFormHook_Action' ), 1 );
94
- add_action( 'comment_form', array( $this, 'printGaspFormParts_Action' ), 2 );
95
- }
 
 
 
96
 
97
- add_filter( 'preprocess_comment', array( $this, 'doCommentPreProcess_Filter' ), 1, 1 );
98
- add_filter( 'pre_comment_content', array( $this, 'doCommentContentPreProcess_Filter' ), 1, 1 );
99
- add_filter( 'pre_comment_approved', array( $this, 'doSetCommentStatus_Filter' ), 1 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  }
101
 
102
  /**
103
  * @param array $aCommentData
104
  * @return array
105
  */
106
- public function doCommentPreProcess_Filter( $aCommentData ) {
107
 
108
  if ( !$this->getIfDoCommentsCheck() ) {
109
  return $aCommentData;
110
  }
111
 
112
  $this->doGaspCommentCheck( $aCommentData['comment_post_ID'] );
113
- $this->doBlacklistSpamCheck( $aCommentData );
114
 
115
  // Now we check whether comment status is to completely reject and then we simply redirect to "home"
116
  if ( $this->sCommentStatus == 'reject' ) {
@@ -121,18 +113,6 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
121
  return $aCommentData;
122
  }
123
 
124
- /**
125
- * @param string $sCommentContent
126
- * @return string
127
- */
128
- public function doCommentContentPreProcess_Filter( $sCommentContent ) {
129
- // If either spam filtering process left an explanation, we add it here
130
- if ( !empty( $this->sCommentStatusExplanation ) ) {
131
- $sCommentContent = $this->sCommentStatusExplanation.$sCommentContent;
132
- }
133
- return $sCommentContent;
134
- }
135
-
136
  /**
137
  * Performs the actual GASP comment checking
138
  *
@@ -152,14 +132,13 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
152
  $fIsSpam = true;
153
  $sExplanation = '';
154
 
155
- $this->loadDataProcessor();
156
-
157
- $sFieldCheckboxName = ICWP_WPSF_DataProcessor::FetchPost( 'cb_nombre' );
158
- $sFieldHoney = ICWP_WPSF_DataProcessor::FetchPost( 'sugar_sweet_email' );
159
- $sFieldCommentToken = ICWP_WPSF_DataProcessor::FetchPost( 'comment_token' );
160
 
161
  // we have the cb name, is it set?
162
- if( !$sFieldCheckboxName || !ICWP_WPSF_DataProcessor::FetchPost( $sFieldCheckboxName ) ) {
163
  $sExplanation = sprintf( _wpsf__('Failed GASP Bot Filter Test (%s)' ), _wpsf__('checkbox') );
164
  $sStatKey = 'checkbox';
165
  }
@@ -184,148 +163,6 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
184
  }
185
  }
186
 
187
- /**
188
- * @param $aCommentData
189
- */
190
- protected function doBlacklistSpamCheck( $aCommentData ) {
191
- $this->loadDataProcessor();
192
- $this->doBlacklistSpamCheck_Action(
193
- $aCommentData['comment_author'],
194
- $aCommentData['comment_author_email'],
195
- $aCommentData['comment_author_url'],
196
- $aCommentData['comment_content'],
197
- long2ip( self::$nRequestIp ),
198
- isset( $_SERVER['HTTP_USER_AGENT'] ) ? substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 ) : ''
199
- );
200
- }
201
-
202
- /**
203
- * Does the same as the WordPress blacklist filter, but more intelligently and with a nod towards much higher performance.
204
- *
205
- * It also uses defined options for which fields are checked for SPAM instead of just checking EVERYTHING!
206
- *
207
- * @param string $sAuthor
208
- * @param string $sEmail
209
- * @param string $sUrl
210
- * @param string $sComment
211
- * @param string $sUserIp
212
- * @param string $sUserAgent
213
- */
214
- public function doBlacklistSpamCheck_Action( $sAuthor, $sEmail, $sUrl, $sComment, $sUserIp, $sUserAgent ) {
215
-
216
- // Check that we haven't already marked the comment through another scan, say GASP
217
- if ( !empty( $this->sCommentStatus ) || !$this->getIsOption('enable_comments_human_spam_filter', 'Y') ) {
218
- return;
219
- }
220
-
221
- // read the file of spam words
222
- $sSpamWords = $this->getSpamBlacklist();
223
- if ( empty($sSpamWords) ) {
224
- return;
225
- }
226
- $aWords = explode( "\n", $sSpamWords );
227
-
228
- $aItemsMap = array(
229
- 'comment_content' => $sComment,
230
- 'url' => $sUrl,
231
- 'author_name' => $sAuthor,
232
- 'author_email' => $sEmail,
233
- 'ip_address' => $sUserIp,
234
- 'user_agent' => $sUserAgent
235
- );
236
- $aDesiredItemsToCheck = $this->getOption('enable_comments_human_spam_filter_items');
237
- $aItemsToCheck = array();
238
- foreach( $aDesiredItemsToCheck as $sKey ) {
239
- $aItemsToCheck[$sKey] = $aItemsMap[$sKey];
240
- }
241
-
242
- foreach( $aItemsToCheck as $sKey => $sItem ) {
243
- foreach ( $aWords as $sWord ) {
244
- if ( stripos( $sItem, $sWord ) !== false ) {
245
- //mark as spam and exit;
246
- $this->doStatIncrement( sprintf( 'spam.human.%s', $sKey ) );
247
- $this->doStatHumanSpamWords( $sWord );
248
- $this->sCommentStatus = $this->getOption('comments_default_action_human_spam');
249
- $this->setCommentStatusExplanation( sprintf( _wpsf__('Human SPAM filter found "%s" in "%s"' ), $sWord, $sKey ) );
250
- break 2;
251
- }
252
- }
253
- }
254
- }
255
-
256
- /**
257
- * @param $sStatWord
258
- */
259
- protected function doStatHumanSpamWords( $sStatWord = '' ) {
260
- $this->loadWpsfStatsProcessor();
261
- if ( !empty( $sStatWord ) ) {
262
- ICWP_Stats_WPSF::DoStatIncrementKeyValue( 'spam.human.words', base64_encode( $sStatWord ) );
263
- }
264
- }
265
-
266
- /**
267
- * @return null|string
268
- */
269
- protected function getSpamBlacklist() {
270
- $oFs = $this->loadFileSystemProcessor();
271
-
272
- // first, does the file exist? If not import
273
- if ( !$oFs->exists( self::$sSpamBlacklistFile ) ) {
274
- $this->doSpamBlacklistImport();
275
- }
276
- // second, if it exists and it's older than 48hrs, update
277
- else if ( self::$nRequestTimestamp - $oFs->getModifiedTime( self::$sSpamBlacklistFile ) > self::TWODAYS ) {
278
- $this->doSpamBlacklistUpdate();
279
- }
280
-
281
- $sList = $oFs->getFileContent( self::$sSpamBlacklistFile );
282
- return empty($sList)? '' : $sList;
283
- }
284
-
285
- /**
286
- */
287
- protected function doSpamBlacklistUpdate() {
288
- $oFs = $this->loadFileSystemProcessor();
289
- $oFs->deleteFile( self::$sSpamBlacklistFile );
290
- $this->doSpamBlacklistImport();
291
- }
292
-
293
- /**
294
- */
295
- protected function doSpamBlacklistImport() {
296
- $oFs = $this->loadFileSystemProcessor();
297
- if ( !$oFs->exists( self::$sSpamBlacklistFile ) ) {
298
-
299
- $sRawList = $this->doSpamBlacklistDownload();
300
-
301
- if ( empty($sRawList) ) {
302
- $sList = '';
303
- }
304
- else {
305
- // filter out empty lines
306
- $aWords = explode( "\n", $sRawList );
307
- foreach ( $aWords as $nIndex => $sWord ) {
308
- $sWord = trim($sWord);
309
- if ( empty($sWord) ) {
310
- unset( $aWords[$nIndex] );
311
- }
312
- }
313
- $sList = implode( "\n", $aWords );
314
- }
315
-
316
- // save the list to disk for the future.
317
- $oFs->putFileContent( self::$sSpamBlacklistFile, $sList );
318
- }
319
- }
320
-
321
- /**
322
- * @return string
323
- */
324
- protected function doSpamBlacklistDownload() {
325
- $oFs = $this->loadFileSystemProcessor();
326
- return $oFs->getUrlContent( self::Spam_Blacklist_Source );
327
- }
328
-
329
  /**
330
  * @return void
331
  */
@@ -337,10 +174,6 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
337
 
338
  $this->deleteOldPostCommentTokens();
339
  $this->insertUniquePostCommentToken();
340
-
341
- $this->loadDataProcessor();
342
- $this->m_sUniqueFormId = ICWP_WPSF_DataProcessor::GenerateRandomString( rand(7, 23), true );
343
-
344
  echo $this->getGaspCommentsHookHtml();
345
  }
346
 
@@ -353,11 +186,8 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
353
 
354
  // Compatibility with shoutbox WP Wall Plugin
355
  // http://wordpress.org/plugins/wp-wall/
356
- if ( function_exists( 'WPWall_Init' ) ) {
357
- $this->loadDataProcessor();
358
- if ( !is_null( ICWP_WPSF_DataProcessor::FetchPost('submit_wall_post') ) ) {
359
- return false;
360
- }
361
  }
362
 
363
  //First, are comments allowed on this post?
@@ -385,14 +215,24 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
385
  // Compatibility with shoutbox WP Wall Plugin
386
  // http://wordpress.org/plugins/wp-wall/
387
  if ( function_exists( 'WPWall_Init' ) ) {
388
- $this->loadDataProcessor();
389
- if ( !is_null( ICWP_WPSF_DataProcessor::FetchPost('submit_wall_post') ) ) {
390
  return false;
391
  }
392
  }
393
  return true;
394
  }
395
 
 
 
 
 
 
 
 
 
 
 
396
  /**
397
  * @return void
398
  */
@@ -406,34 +246,28 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
406
  * @return string
407
  */
408
  protected function getGaspCommentsHookHtml() {
409
- $sId = $this->m_sUniqueFormId;
410
- $sReturn = '<p id="'.$sId.'"></p>'; // we use this unique <p> to hook onto using javascript
411
  $sReturn .= '<input type="hidden" id="_sugar_sweet_email" name="sugar_sweet_email" value="" />';
412
- $sReturn .= '<input type="hidden" id="_comment_token" name="comment_token" value="'.$this->sUniqueCommentToken.'" />';
413
  return $sReturn;
414
  }
415
 
416
  protected function getGaspCommentsHtml() {
417
 
418
- $sId = $this->m_sUniqueFormId;
419
  $sConfirm = stripslashes( $this->getOption('custom_message_checkbox') );
420
  $sAlert = stripslashes( $this->getOption('custom_message_alert') );
421
  $sCommentWait = stripslashes( $this->getOption('custom_message_comment_wait') );
422
  $nCooldown = $this->getOption('comments_cooldown_interval');
423
  $nExpire = $this->getOption('comments_token_expire_interval');
424
 
425
- if ( strpos( $sCommentWait, '%s' ) !== false ) {
426
- $sCommentWait = sprintf( $sCommentWait, $nCooldown );
427
- $sJsCommentWait = str_replace( '%s', '"+nRemaining+"', $this->getOption('custom_message_comment_wait') );
428
- $sJsCommentWait = '"'.$sJsCommentWait.'"';
429
- }
430
- else {
431
- $sJsCommentWait = '"'. $this->getOption('custom_message_comment_wait').'"';
432
- }
433
  $sCommentReload = $this->getOption('custom_message_comment_reload');
434
 
435
  $sReturn = "
436
- <script type='text/javascript'>
437
 
438
  function cb_click$sId() {
439
  cb_name$sId.value=cb$sId.name;
@@ -560,33 +394,7 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
560
  }
561
  }
562
 
563
- /**
564
- * We set the final approval status of the comments if we've set it in our scans, and empties the notification email
565
- * in case we "trash" it (since WP sends out a notification email if it's anything but SPAM)
566
- *
567
- * @param $sApprovalStatus
568
- * @return string
569
- */
570
- public function doSetCommentStatus_Filter( $sApprovalStatus ) {
571
- add_filter( 'comment_notification_recipients', array( $this, 'doClearCommentNotificationEmail_Filter' ), 100, 1 );
572
- return empty( $this->sCommentStatus )? $sApprovalStatus : $this->sCommentStatus;
573
- }
574
-
575
- /**
576
- * When you set a new comment as anything but 'spam' a notification email is sent to the post author.
577
- * We suppress this for when we mark as trash by emptying the email notifications list.
578
- *
579
- * @param $aEmails
580
- * @return array
581
- */
582
- public function doClearCommentNotificationEmail_Filter( $aEmails ) {
583
- if ( $this->sCommentStatus == 'trash' ) {
584
- $aEmails = array();
585
- }
586
- return $aEmails;
587
- }
588
-
589
- public function createTable() {
590
  // Set up comments ID table
591
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
592
  `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -597,8 +405,7 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
597
  `deleted_at` int(15) NOT NULL DEFAULT '0',
598
  PRIMARY KEY (`id`)
599
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
600
- $sSqlTables = sprintf( $sSqlTables, $this->getTableName() );
601
- return $this->doSql( $sSqlTables );
602
  }
603
 
604
  /**
@@ -690,7 +497,7 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
690
  * @return string
691
  */
692
  protected function getUniqueCommentToken() {
693
- if ( !isset( $this->sUniqueCommentToken ) ) {
694
  $this->sUniqueCommentToken = $this->generateUniqueToken();
695
  }
696
  return $this->sUniqueCommentToken;
@@ -721,7 +528,3 @@ class ICWP_CommentsFilterProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
721
  }
722
  }
723
  endif;
724
-
725
- if ( !class_exists('ICWP_WPSF_CommentsFilterProcessor') ):
726
- class ICWP_WPSF_CommentsFilterProcessor extends ICWP_CommentsFilterProcessor_V2 { }
727
- endif;
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( dirname(__FILE__).'/icwp-processor-basedb.php' );
19
 
20
+ if ( !class_exists('ICWP_WPSF_Processor_CommentsFilter_AntiBotSpam') ):
21
 
22
+ class ICWP_WPSF_Processor_CommentsFilter_AntiBotSpam extends ICWP_WPSF_BaseDbProcessor {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  /**
25
  * The unique comment token assigned to this page
28
  protected $sUniqueCommentToken;
29
  /**
30
  * The unique comment token assigned to this page
31
+ * @var string
32
  */
33
+ protected $sUniqueFormId;
34
  /**
35
  * @var string
36
  */
40
  */
41
  protected $sCommentStatusExplanation;
42
 
 
 
 
 
 
 
 
 
43
  /**
44
  * @param ICWP_WPSF_FeatureHandler_CommentsFilter $oFeatureOptions
45
  */
46
  public function __construct( ICWP_WPSF_FeatureHandler_CommentsFilter $oFeatureOptions ) {
47
+ parent::__construct( $oFeatureOptions, $oFeatureOptions->getCommentsFilterTableName() );
 
48
  $this->reset();
49
  }
50
 
56
  $this->sUniqueCommentToken = '';
57
  $this->sCommentStatus = '';
58
  $this->sCommentStatusExplanation = '';
 
59
  }
60
 
61
  /**
64
  parent::run();
65
 
66
  // Add GASP checking to the comment form.
67
+ add_action( 'comment_form', array( $this, 'printGaspFormHook_Action' ), 1 );
68
+ add_action( 'comment_form', array( $this, 'printGaspFormParts_Action' ), 2 );
69
+ add_filter( 'preprocess_comment', array( $this, 'doCommentChecking' ), 1, 1 );
70
+
71
+ add_filter( $this->getFeatureOptions()->doPluginPrefix( 'comments_filter_status' ), array( $this, 'getCommentStatus' ), 1 );
72
+ add_filter( $this->getFeatureOptions()->doPluginPrefix( 'comments_filter_status_explanation' ), array( $this, 'getCommentStatusExplanation' ), 1 );
73
+ }
74
 
75
+ /**
76
+ * A private plugin filter that lets us return up the newly set comment status.
77
+ *
78
+ * @param $sCurrentCommentStatus
79
+ * @return string
80
+ */
81
+ public function getCommentStatus( $sCurrentCommentStatus ) {
82
+ return empty( $sCurrentCommentStatus )? $this->sCommentStatus : $sCurrentCommentStatus;
83
+ }
84
+
85
+ /**
86
+ * A private plugin filter that lets us return up the newly set comment status explanation
87
+ *
88
+ * @param $sCurrentCommentStatusExplanation
89
+ * @return string
90
+ */
91
+ public function getCommentStatusExplanation( $sCurrentCommentStatusExplanation ) {
92
+ return empty( $sCurrentCommentStatusExplanation )? $this->sCommentStatusExplanation : $sCurrentCommentStatusExplanation;
93
  }
94
 
95
  /**
96
  * @param array $aCommentData
97
  * @return array
98
  */
99
+ public function doCommentChecking( $aCommentData ) {
100
 
101
  if ( !$this->getIfDoCommentsCheck() ) {
102
  return $aCommentData;
103
  }
104
 
105
  $this->doGaspCommentCheck( $aCommentData['comment_post_ID'] );
 
106
 
107
  // Now we check whether comment status is to completely reject and then we simply redirect to "home"
108
  if ( $this->sCommentStatus == 'reject' ) {
113
  return $aCommentData;
114
  }
115
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  /**
117
  * Performs the actual GASP comment checking
118
  *
132
  $fIsSpam = true;
133
  $sExplanation = '';
134
 
135
+ $oDp = $this->loadDataProcessor();
136
+ $sFieldCheckboxName = $oDp->FetchPost( 'cb_nombre' );
137
+ $sFieldHoney = $oDp->FetchPost( 'sugar_sweet_email' );
138
+ $sFieldCommentToken = $oDp->FetchPost( 'comment_token' );
 
139
 
140
  // we have the cb name, is it set?
141
+ if( !$sFieldCheckboxName || !$oDp->FetchPost( $sFieldCheckboxName ) ) {
142
  $sExplanation = sprintf( _wpsf__('Failed GASP Bot Filter Test (%s)' ), _wpsf__('checkbox') );
143
  $sStatKey = 'checkbox';
144
  }
163
  }
164
  }
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  /**
167
  * @return void
168
  */
174
 
175
  $this->deleteOldPostCommentTokens();
176
  $this->insertUniquePostCommentToken();
 
 
 
 
177
  echo $this->getGaspCommentsHookHtml();
178
  }
179
 
186
 
187
  // Compatibility with shoutbox WP Wall Plugin
188
  // http://wordpress.org/plugins/wp-wall/
189
+ if ( !$this->getIfDoGaspCheck() ) {
190
+ return false;
 
 
 
191
  }
192
 
193
  //First, are comments allowed on this post?
215
  // Compatibility with shoutbox WP Wall Plugin
216
  // http://wordpress.org/plugins/wp-wall/
217
  if ( function_exists( 'WPWall_Init' ) ) {
218
+ $oDp = $this->loadDataProcessor();
219
+ if ( !is_null( $oDp->FetchPost( 'submit_wall_post' ) ) ) {
220
  return false;
221
  }
222
  }
223
  return true;
224
  }
225
 
226
+ /**
227
+ * @return string
228
+ */
229
+ protected function getUniqueFormId() {
230
+ if ( !isset( $this->sUniqueFormId ) ) {
231
+ $this->sUniqueFormId = $this->loadDataProcessor()->GenerateRandomString( rand(7, 23), true );
232
+ }
233
+ return $this->sUniqueFormId;
234
+ }
235
+
236
  /**
237
  * @return void
238
  */
246
  * @return string
247
  */
248
  protected function getGaspCommentsHookHtml() {
249
+ $sReturn = '<p id="'.$this->getUniqueFormId().'"></p>'; // we use this unique <p> to hook onto using javascript
 
250
  $sReturn .= '<input type="hidden" id="_sugar_sweet_email" name="sugar_sweet_email" value="" />';
251
+ $sReturn .= '<input type="hidden" id="_comment_token" name="comment_token" value="'.$this->getUniqueCommentToken().'" />';
252
  return $sReturn;
253
  }
254
 
255
  protected function getGaspCommentsHtml() {
256
 
257
+ $sId = $this->getUniqueFormId();
258
  $sConfirm = stripslashes( $this->getOption('custom_message_checkbox') );
259
  $sAlert = stripslashes( $this->getOption('custom_message_alert') );
260
  $sCommentWait = stripslashes( $this->getOption('custom_message_comment_wait') );
261
  $nCooldown = $this->getOption('comments_cooldown_interval');
262
  $nExpire = $this->getOption('comments_token_expire_interval');
263
 
264
+ $sJsCommentWait = '"'.str_replace( '%s', '"+nRemaining+"', $sCommentWait ).'"';
265
+ $sCommentWait = str_replace( '%s', $nCooldown, $sCommentWait );
266
+
 
 
 
 
 
267
  $sCommentReload = $this->getOption('custom_message_comment_reload');
268
 
269
  $sReturn = "
270
+ <script type=\"text/javascript\">
271
 
272
  function cb_click$sId() {
273
  cb_name$sId.value=cb$sId.name;
394
  }
395
  }
396
 
397
+ public function getCreateTableSql() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
  // Set up comments ID table
399
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
400
  `id` int(11) NOT NULL AUTO_INCREMENT,
405
  `deleted_at` int(15) NOT NULL DEFAULT '0',
406
  PRIMARY KEY (`id`)
407
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
408
+ return sprintf( $sSqlTables, $this->getTableName() );
 
409
  }
410
 
411
  /**
497
  * @return string
498
  */
499
  protected function getUniqueCommentToken() {
500
+ if ( empty( $this->sUniqueCommentToken ) ) {
501
  $this->sUniqueCommentToken = $this->generateUniqueToken();
502
  }
503
  return $this->sUniqueCommentToken;
528
  }
529
  }
530
  endif;
 
 
 
 
src/icwp-processor-commentsfilter_humanspam.php ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_CommentsFilter_HumanSpam') ):
21
+
22
+ class ICWP_WPSF_Processor_CommentsFilter_HumanSpam extends ICWP_WPSF_Processor_Base {
23
+
24
+ const Spam_Blacklist_Source = 'https://raw.githubusercontent.com/splorp/wordpress-comment-blacklist/master/blacklist.txt';
25
+
26
+ const TWODAYS = 172800;
27
+
28
+ /**
29
+ * @var string
30
+ */
31
+ static protected $sSpamBlacklistFile;
32
+
33
+ /**
34
+ * @var string
35
+ */
36
+ protected $sCommentStatus = '';
37
+ /**
38
+ * @var string
39
+ */
40
+ protected $sCommentStatusExplanation = '';
41
+
42
+ /**
43
+ * @param ICWP_WPSF_FeatureHandler_CommentsFilter $oFeatureOptions
44
+ */
45
+ public function __construct( ICWP_WPSF_FeatureHandler_CommentsFilter $oFeatureOptions ) {
46
+ parent::__construct( $oFeatureOptions );
47
+ $this->reset();
48
+ }
49
+
50
+ /**
51
+ * Resets the object values to be re-used anew
52
+ */
53
+ public function reset() {
54
+ parent::reset();
55
+ $this->sCommentStatus = '';
56
+ $this->sCommentStatusExplanation = '';
57
+ self::$sSpamBlacklistFile = $this->getFeatureOptions()->getResourcesDir().'spamblacklist.txt';
58
+ }
59
+
60
+ /**
61
+ */
62
+ public function run() {
63
+
64
+ add_filter( $this->getFeatureOptions()->doPluginPrefix( 'admin_notices' ), array( $this, 'adminNoticeWarningAkismetRunning' ) );
65
+
66
+ $oDp = $this->loadDataProcessor();
67
+ $oWp = $this->loadWpFunctionsProcessor();
68
+
69
+ if ( $oDp->GetIsRequestPost() && $oWp->getIsCurrentPage( 'wp-comments-post.php' ) ) {
70
+ add_filter( 'preprocess_comment', array( $this, 'doCommentChecking' ), 1, 1 );
71
+ add_filter( $this->getFeatureOptions()->doPluginPrefix( 'comments_filter_status' ), array( $this, 'getCommentStatus' ), 2 );
72
+ add_filter( $this->getFeatureOptions()->doPluginPrefix( 'comments_filter_status_explanation' ), array( $this, 'getCommentStatusExplanation' ), 2 );
73
+ }
74
+ }
75
+
76
+ public function adminNoticeWarningAkismetRunning( $aAdminNotices ) {
77
+ $oWp = $this->loadWpFunctionsProcessor();
78
+
79
+ $sActivePluginFile = $oWp->getIsPluginActive( 'Akismet' );
80
+ if ( $sActivePluginFile ) {
81
+ $sMessage = _wpsf__( 'It appears you have Akismet Anti-SPAM running alongside the Simple Firewall Anti-SPAM.' )
82
+ .' <strong>'._wpsf__('This is not recommended and you should disable Akismet.').'</strong>';
83
+ $sMessage .= '<br />'.sprintf(
84
+ '<a href="%s" id="fromIcwp" class="button">%s</a>',
85
+ $oWp->getPluginDeactivateLink( $sActivePluginFile ),
86
+ _wpsf__( 'Click to deactivate Akismet now' )
87
+ );
88
+ $aAdminNotices[] = $this->getAdminNoticeHtml( $sMessage, 'error' );
89
+ }
90
+ return $aAdminNotices;
91
+ }
92
+
93
+ /**
94
+ * A private plugin filter that lets us return up the newly set comment status.
95
+ *
96
+ * @param $sCurrentCommentStatus
97
+ * @return string
98
+ */
99
+ public function getCommentStatus( $sCurrentCommentStatus ) {
100
+ return empty( $sCurrentCommentStatus )? $this->sCommentStatus : $sCurrentCommentStatus;
101
+ }
102
+
103
+ /**
104
+ * A private plugin filter that lets us return up the newly set comment status explanation
105
+ *
106
+ * @param $sCurrentCommentStatusExplanation
107
+ * @return string
108
+ */
109
+ public function getCommentStatusExplanation( $sCurrentCommentStatusExplanation ) {
110
+ return empty( $sCurrentCommentStatusExplanation )? $this->sCommentStatusExplanation : $sCurrentCommentStatusExplanation;
111
+ }
112
+
113
+ /**
114
+ * Tells us whether, for this particular comment post, if we should do comments checking.
115
+ *
116
+ * @return boolean
117
+ */
118
+ protected function getIfDoCommentsCheck() {
119
+
120
+ // First, are comments allowed on this post?
121
+ global $post;
122
+ if ( !isset( $post ) || $post->comment_status != 'open' ) {
123
+ return false;
124
+ }
125
+
126
+ if ( !is_user_logged_in() ) {
127
+ return true;
128
+ }
129
+ else if ( $this->getIsOption('enable_comments_gasp_protection_for_logged_in', 'Y') ) {
130
+ return true;
131
+ }
132
+ return false;
133
+ }
134
+
135
+ /**
136
+ * @param array $aCommentData
137
+ * @return array
138
+ */
139
+ public function doCommentChecking( $aCommentData ) {
140
+
141
+ if ( !$this->getIfDoCommentsCheck() ) {
142
+ return $aCommentData;
143
+ }
144
+
145
+ $this->doBlacklistSpamCheck( $aCommentData );
146
+
147
+ // Now we check whether comment status is to completely reject and then we simply redirect to "home"
148
+ if ( $this->sCommentStatus == 'reject' ) {
149
+ $oWp = $this->loadWpFunctionsProcessor();
150
+ $oWp->redirectToHome();
151
+ }
152
+
153
+ return $aCommentData;
154
+ }
155
+
156
+ /**
157
+ * @param $aCommentData
158
+ */
159
+ protected function doBlacklistSpamCheck( $aCommentData ) {
160
+ $this->loadDataProcessor();
161
+ $this->doBlacklistSpamCheck_Action(
162
+ $aCommentData['comment_author'],
163
+ $aCommentData['comment_author_email'],
164
+ $aCommentData['comment_author_url'],
165
+ $aCommentData['comment_content'],
166
+ long2ip( self::$nRequestIp ),
167
+ isset( $_SERVER['HTTP_USER_AGENT'] ) ? substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 ) : ''
168
+ );
169
+ }
170
+
171
+ /**
172
+ * Does the same as the WordPress blacklist filter, but more intelligently and with a nod towards much higher performance.
173
+ *
174
+ * It also uses defined options for which fields are checked for SPAM instead of just checking EVERYTHING!
175
+ *
176
+ * @param string $sAuthor
177
+ * @param string $sEmail
178
+ * @param string $sUrl
179
+ * @param string $sComment
180
+ * @param string $sUserIp
181
+ * @param string $sUserAgent
182
+ */
183
+ public function doBlacklistSpamCheck_Action( $sAuthor, $sEmail, $sUrl, $sComment, $sUserIp, $sUserAgent ) {
184
+
185
+ // Check that we haven't already marked the comment through another scan, say GASP
186
+ if ( !empty( $this->sCommentStatus ) || !$this->getIsOption('enable_comments_human_spam_filter', 'Y') ) {
187
+ return;
188
+ }
189
+
190
+ // read the file of spam words
191
+ $sSpamWords = $this->getSpamBlacklist();
192
+ if ( empty($sSpamWords) ) {
193
+ return;
194
+ }
195
+ $aWords = explode( "\n", $sSpamWords );
196
+
197
+ $aItemsMap = array(
198
+ 'comment_content' => $sComment,
199
+ 'url' => $sUrl,
200
+ 'author_name' => $sAuthor,
201
+ 'author_email' => $sEmail,
202
+ 'ip_address' => $sUserIp,
203
+ 'user_agent' => $sUserAgent
204
+ );
205
+ $aDesiredItemsToCheck = $this->getOption('enable_comments_human_spam_filter_items');
206
+ $aItemsToCheck = array();
207
+ foreach( $aDesiredItemsToCheck as $sKey ) {
208
+ $aItemsToCheck[$sKey] = $aItemsMap[$sKey];
209
+ }
210
+
211
+ foreach( $aItemsToCheck as $sKey => $sItem ) {
212
+ foreach ( $aWords as $sWord ) {
213
+ if ( stripos( $sItem, $sWord ) !== false ) {
214
+ //mark as spam and exit;
215
+ $this->doStatIncrement( sprintf( 'spam.human.%s', $sKey ) );
216
+ $this->doStatHumanSpamWords( $sWord );
217
+ $this->sCommentStatus = $this->getOption( 'comments_default_action_human_spam' );
218
+ $this->setCommentStatusExplanation( sprintf( _wpsf__('Human SPAM filter found "%s" in "%s"' ), $sWord, $sKey ) );
219
+ break 2;
220
+ }
221
+ }
222
+ }
223
+ }
224
+
225
+ /**
226
+ * @param $sStatWord
227
+ */
228
+ protected function doStatHumanSpamWords( $sStatWord = '' ) {
229
+ $this->loadStatsProcessor();
230
+ if ( !empty( $sStatWord ) ) {
231
+ ICWP_Stats_WPSF::DoStatIncrementKeyValue( 'spam.human.words', base64_encode( $sStatWord ) );
232
+ }
233
+ }
234
+
235
+ /**
236
+ * @return null|string
237
+ */
238
+ protected function getSpamBlacklist() {
239
+ $oFs = $this->loadFileSystemProcessor();
240
+
241
+ // first, does the file exist? If not import
242
+ if ( !$oFs->exists( self::$sSpamBlacklistFile ) ) {
243
+ $this->doSpamBlacklistImport();
244
+ }
245
+ // second, if it exists and it's older than 48hrs, update
246
+ else if ( self::$nRequestTimestamp - $oFs->getModifiedTime( self::$sSpamBlacklistFile ) > self::TWODAYS ) {
247
+ $this->doSpamBlacklistUpdate();
248
+ }
249
+
250
+ $sList = $oFs->getFileContent( self::$sSpamBlacklistFile );
251
+ return empty($sList)? '' : $sList;
252
+ }
253
+
254
+ /**
255
+ */
256
+ protected function doSpamBlacklistUpdate() {
257
+ $oFs = $this->loadFileSystemProcessor();
258
+ $oFs->deleteFile( self::$sSpamBlacklistFile );
259
+ $this->doSpamBlacklistImport();
260
+ }
261
+
262
+ /**
263
+ */
264
+ protected function doSpamBlacklistImport() {
265
+ $oFs = $this->loadFileSystemProcessor();
266
+ if ( !$oFs->exists( self::$sSpamBlacklistFile ) ) {
267
+
268
+ $sRawList = $this->doSpamBlacklistDownload();
269
+
270
+ if ( empty($sRawList) ) {
271
+ $sList = '';
272
+ }
273
+ else {
274
+ // filter out empty lines
275
+ $aWords = explode( "\n", $sRawList );
276
+ foreach ( $aWords as $nIndex => $sWord ) {
277
+ $sWord = trim($sWord);
278
+ if ( empty($sWord) ) {
279
+ unset( $aWords[$nIndex] );
280
+ }
281
+ }
282
+ $sList = implode( "\n", $aWords );
283
+ }
284
+
285
+ // save the list to disk for the future.
286
+ $oFs->putFileContent( self::$sSpamBlacklistFile, $sList );
287
+ }
288
+ }
289
+
290
+ /**
291
+ * @return string
292
+ */
293
+ protected function doSpamBlacklistDownload() {
294
+ $oFs = $this->loadFileSystemProcessor();
295
+ return $oFs->getUrlContent( self::Spam_Blacklist_Source );
296
+ }
297
+
298
+ /**
299
+ * @param $sExplanation
300
+ */
301
+ protected function setCommentStatusExplanation( $sExplanation ) {
302
+ $this->sCommentStatusExplanation =
303
+ '[* '.sprintf( _wpsf__('WordPress Simple Firewall plugin marked this comment as "%s" because: %s.'),
304
+ $this->sCommentStatus,
305
+ $sExplanation
306
+ )." *]\n";
307
+ }
308
+ }
309
+ endif;
src/icwp-processor-email.php CHANGED
@@ -15,11 +15,11 @@
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
- require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
  if ( !class_exists('ICWP_EmailProcessor_V1') ):
21
 
22
- class ICWP_EmailProcessor_V1 extends ICWP_WPSF_BaseProcessor {
23
 
24
  const Slug = 'email';
25
 
@@ -179,7 +179,7 @@ class ICWP_EmailProcessor_V1 extends ICWP_WPSF_BaseProcessor {
179
  */
180
  public function getDefaultRecipientAddress() {
181
  $oWpFunctions = $this->loadWpFunctionsProcessor();
182
- return apply_filters( $this->oFeatureOptions->doPluginPrefix( 'report_email_address' ), $oWpFunctions->getSiteAdminEmail() );
183
  }
184
 
185
  /**
@@ -200,6 +200,6 @@ class ICWP_EmailProcessor_V1 extends ICWP_WPSF_BaseProcessor {
200
 
201
  endif;
202
 
203
- if ( !class_exists('ICWP_WPSF_EmailProcessor') ):
204
- class ICWP_WPSF_EmailProcessor extends ICWP_EmailProcessor_V1 { }
205
  endif;
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
 
20
  if ( !class_exists('ICWP_EmailProcessor_V1') ):
21
 
22
+ class ICWP_EmailProcessor_V1 extends ICWP_WPSF_Processor_Base {
23
 
24
  const Slug = 'email';
25
 
179
  */
180
  public function getDefaultRecipientAddress() {
181
  $oWpFunctions = $this->loadWpFunctionsProcessor();
182
+ return apply_filters( $this->getFeatureOptions()->doPluginPrefix( 'report_email_address' ), $oWpFunctions->getSiteAdminEmail() );
183
  }
184
 
185
  /**
200
 
201
  endif;
202
 
203
+ if ( !class_exists('ICWP_WPSF_Processor_Email') ):
204
+ class ICWP_WPSF_Processor_Email extends ICWP_EmailProcessor_V1 { }
205
  endif;
src/icwp-processor-firewall.php CHANGED
@@ -15,11 +15,11 @@
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
- require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
  if ( !class_exists('ICWP_FirewallProcessor_V1') ):
21
 
22
- class ICWP_FirewallProcessor_V1 extends ICWP_WPSF_BaseProcessor {
23
 
24
  protected $m_aWhitelistPages;
25
  protected $m_aWhitelistPagesPatterns;
@@ -73,25 +73,7 @@ class ICWP_FirewallProcessor_V1 extends ICWP_WPSF_BaseProcessor {
73
  $sMessage = _wpsf__( "You were blocked by the %sWordPress Simple Firewall%s." );
74
  $this->m_sFirewallMessage = sprintf( $sMessage, '<a href="http://wordpress.org/plugins/wp-simple-firewall/" target="_blank">', '</a>');
75
  }
76
-
77
- /**
78
- * @see ICWP_WPSF_BaseProcessor::setOptions()
79
- */
80
- public function setOptions( &$aOptions ) {
81
- parent::setOptions( $aOptions );
82
- $this->m_aCustomWhitelistPageParams = is_array( $this->getOption( 'page_params_whitelist' ) )? $this->getOption( 'page_params_whitelist' ) : array();
83
- }
84
 
85
- /**
86
- * @return boolean
87
- */
88
- public function getNeedsEmailHandler() {
89
- if ( $this->getIsOption( 'block_send_email', 'Y' ) ) {
90
- return true;
91
- }
92
- return false;
93
- }
94
-
95
  public function reset() {
96
  parent::reset();
97
  $this->m_nLoopProtect = 0;
@@ -109,7 +91,7 @@ class ICWP_FirewallProcessor_V1 extends ICWP_WPSF_BaseProcessor {
109
  * Should return false when logging is disabled.
110
  *
111
  * @return false|array - false when logging is disabled, array with log data otherwise
112
- * @see ICWP_WPSF_BaseProcessor::getLogData()
113
  */
114
  public function flushLogData() {
115
 
@@ -154,8 +136,8 @@ class ICWP_FirewallProcessor_V1 extends ICWP_WPSF_BaseProcessor {
154
  return true;
155
  }
156
 
157
- $this->loadDataProcessor();
158
- if ( $this->getOption('ignore_search_engines') == 'Y' && ICWP_WPSF_DataProcessor::IsSearchEngineBot() ) {
159
  $this->logInfo( _wpsf__('Visitor detected as Search Engine Bot so by-passing Firewall Checking.') );
160
  return true;
161
  }
@@ -591,7 +573,7 @@ class ICWP_FirewallProcessor_V1 extends ICWP_WPSF_BaseProcessor {
591
  )
592
  );
593
 
594
- $aCustomWhitelistPageParams = is_array( $this->getOption( 'page_params_whitelist' ) )? $this->getOption( 'page_params_whitelist' ) : array();
595
  $this->m_aWhitelistPages = array_merge( $aDefaultWlPages, $aCustomWhitelistPageParams );
596
 
597
  $this->m_aWhitelistPagesPatterns = array(
@@ -637,6 +619,6 @@ class ICWP_FirewallProcessor_V1 extends ICWP_WPSF_BaseProcessor {
637
 
638
  endif;
639
 
640
- if ( !class_exists('ICWP_WPSF_FirewallProcessor') ):
641
- class ICWP_WPSF_FirewallProcessor extends ICWP_FirewallProcessor_V1 { }
642
  endif;
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
 
20
  if ( !class_exists('ICWP_FirewallProcessor_V1') ):
21
 
22
+ class ICWP_FirewallProcessor_V1 extends ICWP_WPSF_Processor_Base {
23
 
24
  protected $m_aWhitelistPages;
25
  protected $m_aWhitelistPagesPatterns;
73
  $sMessage = _wpsf__( "You were blocked by the %sWordPress Simple Firewall%s." );
74
  $this->m_sFirewallMessage = sprintf( $sMessage, '<a href="http://wordpress.org/plugins/wp-simple-firewall/" target="_blank">', '</a>');
75
  }
 
 
 
 
 
 
 
 
76
 
 
 
 
 
 
 
 
 
 
 
77
  public function reset() {
78
  parent::reset();
79
  $this->m_nLoopProtect = 0;
91
  * Should return false when logging is disabled.
92
  *
93
  * @return false|array - false when logging is disabled, array with log data otherwise
94
+ * @see ICWP_WPSF_Processor_Base::getLogData()
95
  */
96
  public function flushLogData() {
97
 
136
  return true;
137
  }
138
 
139
+ $oDp = $this->loadDataProcessor();
140
+ if ( $this->getOption('ignore_search_engines') == 'Y' && $oDp->IsSearchEngineBot() ) {
141
  $this->logInfo( _wpsf__('Visitor detected as Search Engine Bot so by-passing Firewall Checking.') );
142
  return true;
143
  }
573
  )
574
  );
575
 
576
+ $aCustomWhitelistPageParams = is_array( $this->getOption( 'page_params_whitelist' ) )? $this->getOption( 'page_params_whitelist' ) : array();
577
  $this->m_aWhitelistPages = array_merge( $aDefaultWlPages, $aCustomWhitelistPageParams );
578
 
579
  $this->m_aWhitelistPagesPatterns = array(
619
 
620
  endif;
621
 
622
+ if ( !class_exists('ICWP_WPSF_Processor_Firewall') ):
623
+ class ICWP_WPSF_Processor_Firewall extends ICWP_FirewallProcessor_V1 { }
624
  endif;
src/icwp-processor-lockdown.php CHANGED
@@ -15,136 +15,140 @@
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
- require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
  if ( !class_exists('ICWP_LockdownProcessor_V1') ):
21
 
22
- class ICWP_LockdownProcessor_V1 extends ICWP_WPSF_BaseProcessor {
23
 
24
- /**
25
- * @param ICWP_WPSF_FeatureHandler_Lockdown $oFeatureOptions
26
- */
27
- public function __construct( ICWP_WPSF_FeatureHandler_Lockdown $oFeatureOptions ) {
28
- parent::__construct( $oFeatureOptions );
29
- }
30
 
31
- /**
32
- */
33
- public function run() {
34
-
35
- if ( $this->getIsOption( 'disable_file_editing', 'Y' ) ) {
36
- if ( !defined('DISALLOW_FILE_EDIT') ) {
37
- define( 'DISALLOW_FILE_EDIT', true );
 
 
38
  }
39
- add_filter( 'user_has_cap', array( $this, 'disableFileEditing' ), 0, 3 );
40
- }
41
 
42
- $sWpVersionMask = $this->getOption('mask_wordpress_version');
43
- if ( !empty( $sWpVersionMask ) ) {
44
- global $wp_version;
45
- $wp_version = $sWpVersionMask;
46
  // add_filter( 'bloginfo', array( $this, 'maskWordpressVersion' ), 1, 2 );
47
  // add_filter( 'bloginfo_url', array( $this, 'maskWordpressVersion' ), 1, 2 );
48
- }
49
 
50
- if ( false && $this->getOption('action_reset_auth_salts') == 'Y' ) {
51
- add_action( 'init', array( $this, 'resetAuthKeysSalts' ), 1 );
52
- }
53
 
54
- if ( $this->getIsOption( 'force_ssl_login', 'Y' ) && function_exists('force_ssl_login') ) {
55
- if ( !defined('FORCE_SSL_LOGIN') ) {
56
- define( 'FORCE_SSL_LOGIN', true );
 
 
57
  }
58
- force_ssl_login( true );
59
- }
60
 
61
- if ( $this->getIsOption( 'force_ssl_admin', 'Y' ) && function_exists('force_ssl_admin') ) {
62
- if ( !defined('FORCE_SSL_ADMIN') ) {
63
- define( 'FORCE_SSL_ADMIN', true );
 
 
64
  }
65
- force_ssl_admin( true );
66
- }
67
 
68
- if ( $this->getIsOption( 'hide_wordpress_generator_tag', 'Y' ) ) {
69
- remove_action( 'wp_head', 'wp_generator' );
 
70
  }
71
- }
72
 
73
- /**
74
- * @return array
75
- */
76
- public function disableFileEditing( $aAllCaps, $cap, $aArgs ) {
77
-
78
- $aEditCapabilities = array( 'edit_themes', 'edit_plugins', 'edit_files' );
79
- $sRequestedCapability = $aArgs[0];
80
-
81
- if ( !in_array( $sRequestedCapability, $aEditCapabilities ) ) {
 
 
 
 
 
 
82
  return $aAllCaps;
83
  }
84
- $aAllCaps[ $sRequestedCapability ] = false;
85
- return $aAllCaps;
86
- }
87
-
88
- /**
89
- * @return array
90
- */
91
- public function maskWordpressVersion( $insOutput, $insShow ) {
92
- // if ( $insShow === 'version' ) {
93
- // $insOutput = $this->aOptions['mask_wordpress_version'];
94
  // }
95
- // return $insOutput;
96
- }
97
-
98
- /**
99
- *
100
- */
101
- public function resetAuthKeysSalts() {
102
- $oWpFs = $this->loadFileSystemProcessor();
103
-
104
- // Get the new Salts
105
- $sSaltsUrl = 'https://api.wordpress.org/secret-key/1.1/salt/';
106
- $sSalts = $oWpFs->getUrlContent( $sSaltsUrl );
107
-
108
- $sWpConfigContent = $oWpFs->getContent_WpConfig();
109
- if ( is_null( $sWpConfigContent ) ) {
110
- return;
111
  }
112
-
113
- $aKeys = array(
114
- 'AUTH_KEY',
115
- 'SECURE_AUTH_KEY',
116
- 'LOGGED_IN_KEY',
117
- 'NONCE_KEY',
118
- 'AUTH_SALT',
119
- 'SECURE_AUTH_SALT',
120
- 'LOGGED_IN_SALT',
121
- 'NONCE_SALT'
122
- );
123
-
124
- $aContent = explode( PHP_EOL, $sWpConfigContent );
125
- $fKeyFound = false;
126
- $nStartLine = 0;
127
- foreach( $aContent as $nLineNumber => $sLine ) {
128
- foreach( $aKeys as $nPosition => $sKey ) {
129
- if ( strpos( $sLine, $sKey ) === false ) {
130
- continue;
131
- }
132
- if ( $nStartLine == 0 ) {
133
- $nStartLine = $nLineNumber;
134
- }
135
- else {
136
- unset( $aContent[ $nLineNumber ] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  }
138
- $fKeyFound = true;
139
  }
 
 
140
  }
141
- $aContent[$nStartLine] = $sSalts;
142
- $oWpFs->putContent_WpConfig( implode( PHP_EOL, $aContent ) );
143
  }
144
- }
145
 
146
  endif;
147
 
148
- if ( !class_exists('ICWP_WPSF_LockdownProcessor') ):
149
- class ICWP_WPSF_LockdownProcessor extends ICWP_LockdownProcessor_V1 { }
150
  endif;
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
 
20
  if ( !class_exists('ICWP_LockdownProcessor_V1') ):
21
 
22
+ class ICWP_LockdownProcessor_V1 extends ICWP_WPSF_Processor_Base {
23
 
24
+ /**
25
+ * @param ICWP_WPSF_FeatureHandler_Lockdown $oFeatureOptions
26
+ */
27
+ public function __construct( ICWP_WPSF_FeatureHandler_Lockdown $oFeatureOptions ) {
28
+ parent::__construct( $oFeatureOptions );
29
+ }
30
 
31
+ /**
32
+ */
33
+ public function run() {
34
+
35
+ if ( $this->getIsOption( 'disable_file_editing', 'Y' ) ) {
36
+ if ( !defined('DISALLOW_FILE_EDIT') ) {
37
+ define( 'DISALLOW_FILE_EDIT', true );
38
+ }
39
+ add_filter( 'user_has_cap', array( $this, 'disableFileEditing' ), 0, 3 );
40
  }
 
 
41
 
42
+ $sWpVersionMask = $this->getOption('mask_wordpress_version');
43
+ if ( !empty( $sWpVersionMask ) ) {
44
+ global $wp_version;
45
+ $wp_version = $sWpVersionMask;
46
  // add_filter( 'bloginfo', array( $this, 'maskWordpressVersion' ), 1, 2 );
47
  // add_filter( 'bloginfo_url', array( $this, 'maskWordpressVersion' ), 1, 2 );
48
+ }
49
 
50
+ if ( false && $this->getOption('action_reset_auth_salts') == 'Y' ) {
51
+ add_action( 'init', array( $this, 'resetAuthKeysSalts' ), 1 );
52
+ }
53
 
54
+ if ( $this->getIsOption( 'force_ssl_login', 'Y' ) && function_exists('force_ssl_login') ) {
55
+ if ( !defined('FORCE_SSL_LOGIN') ) {
56
+ define( 'FORCE_SSL_LOGIN', true );
57
+ }
58
+ force_ssl_login( true );
59
  }
 
 
60
 
61
+ if ( $this->getIsOption( 'force_ssl_admin', 'Y' ) && function_exists('force_ssl_admin') ) {
62
+ if ( !defined('FORCE_SSL_ADMIN') ) {
63
+ define( 'FORCE_SSL_ADMIN', true );
64
+ }
65
+ force_ssl_admin( true );
66
  }
 
 
67
 
68
+ if ( $this->getIsOption( 'hide_wordpress_generator_tag', 'Y' ) ) {
69
+ remove_action( 'wp_head', 'wp_generator' );
70
+ }
71
  }
 
72
 
73
+ /**
74
+ * @param array $aAllCaps
75
+ * @param $cap
76
+ * @param array $aArgs
77
+ * @return array
78
+ */
79
+ public function disableFileEditing( $aAllCaps, $cap, $aArgs ) {
80
+
81
+ $aEditCapabilities = array( 'edit_themes', 'edit_plugins', 'edit_files' );
82
+ $sRequestedCapability = $aArgs[0];
83
+
84
+ if ( !in_array( $sRequestedCapability, $aEditCapabilities ) ) {
85
+ return $aAllCaps;
86
+ }
87
+ $aAllCaps[ $sRequestedCapability ] = false;
88
  return $aAllCaps;
89
  }
90
+
91
+ /**
92
+ * @param $sOutput
93
+ * @param $sShow
94
+ * @return string
95
+ */
96
+ public function maskWordpressVersion( $sOutput, $sShow ) {
97
+ // if ( $sShow === 'version' ) {
98
+ // $sOutput = $this->aOptions['mask_wordpress_version'];
 
99
  // }
100
+ // return $sOutput;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  }
102
+
103
+ /**
104
+ */
105
+ public function resetAuthKeysSalts() {
106
+ $oWpFs = $this->loadFileSystemProcessor();
107
+
108
+ // Get the new Salts
109
+ $sSaltsUrl = 'https://api.wordpress.org/secret-key/1.1/salt/';
110
+ $sSalts = $oWpFs->getUrlContent( $sSaltsUrl );
111
+
112
+ $sWpConfigContent = $oWpFs->getContent_WpConfig();
113
+ if ( is_null( $sWpConfigContent ) ) {
114
+ return;
115
+ }
116
+
117
+ $aKeys = array(
118
+ 'AUTH_KEY',
119
+ 'SECURE_AUTH_KEY',
120
+ 'LOGGED_IN_KEY',
121
+ 'NONCE_KEY',
122
+ 'AUTH_SALT',
123
+ 'SECURE_AUTH_SALT',
124
+ 'LOGGED_IN_SALT',
125
+ 'NONCE_SALT'
126
+ );
127
+
128
+ $aContent = explode( PHP_EOL, $sWpConfigContent );
129
+ $fKeyFound = false;
130
+ $nStartLine = 0;
131
+ foreach( $aContent as $nLineNumber => $sLine ) {
132
+ foreach( $aKeys as $nPosition => $sKey ) {
133
+ if ( strpos( $sLine, $sKey ) === false ) {
134
+ continue;
135
+ }
136
+ if ( $nStartLine == 0 ) {
137
+ $nStartLine = $nLineNumber;
138
+ }
139
+ else {
140
+ unset( $aContent[ $nLineNumber ] );
141
+ }
142
+ $fKeyFound = true;
143
  }
 
144
  }
145
+ $aContent[$nStartLine] = $sSalts;
146
+ $oWpFs->putContent_WpConfig( implode( PHP_EOL, $aContent ) );
147
  }
 
 
148
  }
 
149
 
150
  endif;
151
 
152
+ if ( !class_exists('ICWP_WPSF_Processor_Lockdown') ):
153
+ class ICWP_WPSF_Processor_Lockdown extends ICWP_LockdownProcessor_V1 { }
154
  endif;
src/icwp-processor-logging.php CHANGED
@@ -15,13 +15,12 @@
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
- require_once( dirname(__FILE__).'/icwp-basedb-processor.php' );
19
 
20
  if ( !class_exists('ICWP_LoggingProcessor_V1') ):
21
 
22
- class ICWP_LoggingProcessor_V1 extends ICWP_BaseDbProcessor_WPSF {
23
 
24
- const TableName = 'wpsf_log';
25
  const DaysToKeepLog = 7;
26
 
27
  protected $sVisitorRequestId;
@@ -30,11 +29,9 @@ class ICWP_LoggingProcessor_V1 extends ICWP_BaseDbProcessor_WPSF {
30
  * @param ICWP_WPSF_FeatureHandler_Logging $oFeatureOptions
31
  */
32
  public function __construct( ICWP_WPSF_FeatureHandler_Logging $oFeatureOptions ) {
33
- parent::__construct( $oFeatureOptions, self::TableName );
34
- $this->createTable();
35
  }
36
 
37
-
38
  public function reset() {
39
  parent::reset();
40
  $this->m_sRequestId = uniqid();
@@ -77,8 +74,11 @@ class ICWP_LoggingProcessor_V1 extends ICWP_BaseDbProcessor_WPSF {
77
  }
78
  return $inaLogData;
79
  }
80
-
81
- public function createTable() {
 
 
 
82
  // Set up log table
83
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
84
  `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -91,8 +91,7 @@ class ICWP_LoggingProcessor_V1 extends ICWP_BaseDbProcessor_WPSF {
91
  `deleted_at` int(15) NOT NULL DEFAULT '0',
92
  PRIMARY KEY (`id`)
93
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
94
- $sSqlTables = sprintf( $sSqlTables, $this->getTableName() );
95
- return $this->doSql( $sSqlTables );
96
  }
97
 
98
  public function handleInstallUpgrade( $insCurrentVersion = '' ) {
@@ -118,6 +117,6 @@ class ICWP_LoggingProcessor_V1 extends ICWP_BaseDbProcessor_WPSF {
118
 
119
  endif;
120
 
121
- if ( !class_exists('ICWP_WPSF_LoggingProcessor') ):
122
- class ICWP_WPSF_LoggingProcessor extends ICWP_LoggingProcessor_V1 { }
123
  endif;
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( dirname(__FILE__).'/icwp-processor-basedb.php' );
19
 
20
  if ( !class_exists('ICWP_LoggingProcessor_V1') ):
21
 
22
+ class ICWP_LoggingProcessor_V1 extends ICWP_WPSF_BaseDbProcessor {
23
 
 
24
  const DaysToKeepLog = 7;
25
 
26
  protected $sVisitorRequestId;
29
  * @param ICWP_WPSF_FeatureHandler_Logging $oFeatureOptions
30
  */
31
  public function __construct( ICWP_WPSF_FeatureHandler_Logging $oFeatureOptions ) {
32
+ parent::__construct( $oFeatureOptions, $oFeatureOptions->getGeneralLoggingTableName() );
 
33
  }
34
 
 
35
  public function reset() {
36
  parent::reset();
37
  $this->m_sRequestId = uniqid();
74
  }
75
  return $inaLogData;
76
  }
77
+
78
+ /**
79
+ * @return string
80
+ */
81
+ public function getCreateTableSql() {
82
  // Set up log table
83
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
84
  `id` int(11) NOT NULL AUTO_INCREMENT,
91
  `deleted_at` int(15) NOT NULL DEFAULT '0',
92
  PRIMARY KEY (`id`)
93
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
94
+ return sprintf( $sSqlTables, $this->getTableName() );
 
95
  }
96
 
97
  public function handleInstallUpgrade( $insCurrentVersion = '' ) {
117
 
118
  endif;
119
 
120
+ if ( !class_exists('ICWP_WPSF_Processor_Logging') ):
121
+ class ICWP_WPSF_Processor_Logging extends ICWP_LoggingProcessor_V1 { }
122
  endif;
src/icwp-processor-login_protect.php ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_LoginProtect_V4') ):
21
+
22
+ class ICWP_WPSF_Processor_LoginProtect_V4 extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_LoginProtect
26
+ */
27
+ protected $oFeatureOptions;
28
+
29
+ /**
30
+ * @var ICWP_WPSF_Processor_LoginProtect_Gasp
31
+ */
32
+ protected $oProcessorGasp;
33
+
34
+ /**
35
+ * @var ICWP_WPSF_Processor_LoginProtect_Cooldown
36
+ */
37
+ protected $oProcessorCooldown;
38
+
39
+ /**
40
+ * @var ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth
41
+ */
42
+ protected $oProcessorTwoFactor;
43
+
44
+ /**
45
+ * @var ICWP_WPSF_Processor_LoginProtect_Yubikey
46
+ */
47
+ protected $oProcessorYubikey;
48
+
49
+ /**
50
+ * @param ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions
51
+ */
52
+ public function __construct( ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions ) {
53
+ parent::__construct( $oFeatureOptions );
54
+ $this->reset();
55
+ }
56
+
57
+ /**
58
+ * @return bool|void
59
+ */
60
+ public function getIsLogging() {
61
+ return $this->getIsOption( 'enable_login_protect_log', 'Y' );
62
+ }
63
+
64
+ /**
65
+ */
66
+ public function run() {
67
+ parent::run();
68
+ $oDp = $this->loadDataProcessor();
69
+ $fIsPost = $oDp->GetIsRequestPost();
70
+
71
+ $aWhitelist = $this->getOption( 'ips_whitelist', array() );
72
+ if ( !empty( $aWhitelist ) && $this->isIpOnlist( $aWhitelist, self::$nRequestIp ) ) {
73
+ return true;
74
+ }
75
+
76
+ $oWp = $this->oFeatureOptions->loadWpFunctionsProcessor();
77
+ // XML-RPC Compatibility
78
+ if ( $oWp->getIsXmlrpc() && $this->getIsOption( 'enable_xmlrpc_compatibility', 'Y' ) ) {
79
+ return true;
80
+ }
81
+
82
+ // check for remote posting before anything else.
83
+ if ( $fIsPost && $this->getIsOption( 'enable_prevent_remote_post', 'Y' ) ) {
84
+ add_filter( 'authenticate', array( $this, 'checkRemotePostLogin_Filter' ), 9, 3);
85
+ }
86
+
87
+ // Add GASP checking to the login form.
88
+ if ( $this->getIsOption( 'enable_login_gasp_check', 'Y' ) ) {
89
+ $this->getProcessorGasp()->run();
90
+ }
91
+
92
+ if ( $fIsPost && $this->getOption( 'login_limit_interval' ) > 0 ) {
93
+ $this->getProcessorCooldown()->run();
94
+ }
95
+
96
+ // check for Yubikey auth after user is authenticated with WordPress.
97
+ if ( $this->getIsOption( 'enable_yubikey', 'Y' ) ) {
98
+ $this->getProcessorYubikey()->run();
99
+ }
100
+
101
+ if ( $this->oFeatureOptions->getIsTwoFactorAuthOn() ) {
102
+ $this->getProcessorTwoFactor()->run();
103
+ }
104
+
105
+ add_filter( 'wp_login_errors', array( $this, 'addLoginMessage' ) );
106
+ }
107
+
108
+ /**
109
+ * @param WP_Error $oError
110
+ * @return WP_Error
111
+ */
112
+ public function addLoginMessage( $oError ) {
113
+
114
+ if ( ! $oError instanceof WP_Error ) {
115
+ $oError = new WP_Error();
116
+ }
117
+
118
+ $oDp = $this->loadDataProcessor();
119
+ $sForceLogout = $oDp->FetchGet( 'wpsf-forcelogout' );
120
+ if ( $sForceLogout == 6 ) {
121
+ $oError->add( 'wpsf-forcelogout', _wpsf__('Your Two-Factor Authentication Was Verified.').'<br />'._wpsf__('Please login again.') );
122
+ }
123
+ return $oError;
124
+ }
125
+
126
+ /**
127
+ * @param $oUser
128
+ * @param $sUsername
129
+ * @param $sPassword
130
+ * @return mixed
131
+ */
132
+ public function checkRemotePostLogin_Filter( $oUser, $sUsername, $sPassword ) {
133
+ $oDp = $this->loadDataProcessor();
134
+ $sHttpRef = $oDp->FetchServer( 'HTTP_REFERER' );
135
+
136
+ if ( !empty( $sHttpRef ) ) {
137
+ $aHttpRefererParts = parse_url( $sHttpRef );
138
+ $aHomeUrlParts = parse_url( home_url() );
139
+
140
+ if ( !empty( $aHttpRefererParts['host'] ) && !empty( $aHomeUrlParts['host'] ) && ( $aHttpRefererParts['host'] === $aHomeUrlParts['host'] ) ) {
141
+ $this->doStatIncrement( 'login.remotepost.success' );
142
+ return $oUser;
143
+ }
144
+ }
145
+
146
+ $this->logWarning(
147
+ sprintf( _wpsf__('User "%s" attempted to login but the HTTP REFERER was either empty or it was a remote login attempt. Bot Perhaps? HTTP REFERER: "%s".'), $sUsername, $sHttpRef )
148
+ );
149
+ $this->doStatIncrement( 'login.remotepost.fail' );
150
+ wp_die(
151
+ _wpsf__( 'Sorry, you must login directly from within the site.' )
152
+ .' '._wpsf__( 'Remote login is not supported.' )
153
+ .'<br /><a href="http://icwp.io/4n" target="_blank">&rarr;'._wpsf__('More Info').'</a>'
154
+ );
155
+ }
156
+
157
+ /**
158
+ * Should return false when logging is disabled.
159
+ *
160
+ * @return false|array - false when logging is disabled, array with log data otherwise
161
+ * @see ICWP_WPSF_Processor_Base::getLogData()
162
+ */
163
+ public function flushLogData() {
164
+
165
+ if ( !$this->getIsLogging() || empty( $this->m_aLogMessages ) ) {
166
+ return false;
167
+ }
168
+
169
+ $this->m_aLog = array(
170
+ 'category' => self::LOG_CATEGORY_LOGINPROTECT,
171
+ 'messages' => serialize( $this->m_aLogMessages )
172
+ );
173
+ $this->resetLog();
174
+ return $this->m_aLog;
175
+ }
176
+
177
+ /**
178
+ * @return ICWP_WPSF_Processor_LoginProtect_Cooldown
179
+ */
180
+ protected function getProcessorCooldown() {
181
+ if ( !isset( $this->oProcessorCooldown ) ) {
182
+ require_once('icwp-processor-loginprotect_cooldown.php');
183
+ $this->oProcessorCooldown = new ICWP_WPSF_Processor_LoginProtect_Cooldown( $this->oFeatureOptions );
184
+ }
185
+ return $this->oProcessorCooldown;
186
+ }
187
+
188
+ /**
189
+ * @return ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth
190
+ */
191
+ protected function getProcessorTwoFactor() {
192
+ if ( !isset( $this->oProcessorTwoFactor ) ) {
193
+ require_once('icwp-processor-loginprotect_twofactorauth.php');
194
+ $this->oProcessorTwoFactor = new ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth( $this->oFeatureOptions );
195
+ }
196
+ return $this->oProcessorTwoFactor;
197
+ }
198
+
199
+ /**
200
+ * @return ICWP_WPSF_Processor_LoginProtect_Gasp
201
+ */
202
+ protected function getProcessorGasp() {
203
+ if ( !isset( $this->oProcessorGasp ) ) {
204
+ require_once( 'icwp-processor-loginprotect_gasp.php' );
205
+ $this->oProcessorGasp = new ICWP_WPSF_Processor_LoginProtect_Gasp( $this->oFeatureOptions );
206
+ }
207
+ return $this->oProcessorGasp;
208
+ }
209
+
210
+ /**
211
+ * @return ICWP_WPSF_Processor_LoginProtect_Yubikey
212
+ */
213
+ protected function getProcessorYubikey() {
214
+ if ( !isset( $this->oProcessorYubikey ) ) {
215
+ require_once('icwp-processor-loginprotect_yubikey.php');
216
+ $this->oProcessorYubikey = new ICWP_WPSF_Processor_LoginProtect_Yubikey( $this->oFeatureOptions );
217
+ }
218
+ return $this->oProcessorYubikey;
219
+ }
220
+ }
221
+ endif;
222
+
223
+ if ( !class_exists('ICWP_WPSF_Processor_LoginProtect') ):
224
+ class ICWP_WPSF_Processor_LoginProtect extends ICWP_WPSF_Processor_LoginProtect_V4 { }
225
+ endif;
src/icwp-processor-loginprotect.php DELETED
@@ -1,1030 +0,0 @@
1
- <?php
2
- /**
3
- * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
- * All rights reserved.
5
- *
6
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
- */
17
-
18
- require_once( dirname(__FILE__).'/icwp-basedb-processor.php' );
19
-
20
- if ( !class_exists('ICWP_LoginProtectProcessor_V3') ):
21
-
22
- class ICWP_LoginProtectProcessor_V3 extends ICWP_BaseDbProcessor_WPSF {
23
-
24
- const TableName = 'login_auth';
25
- const AuthActiveCookie = 'wpsf_auth';
26
- const YubikeyVerifyApiUrl = 'https://api.yubico.com/wsapi/2.0/verify?id=%s&otp=%s&nonce=%s';
27
-
28
- /**
29
- * @var ICWP_WPSF_FeatureHandler_LoginProtect
30
- */
31
- protected $oFeatureOptions;
32
-
33
- /**
34
- * @var string
35
- */
36
- static protected $sModeFile_LoginThrottled;
37
-
38
- /**
39
- * The number of seconds between each authenticated login
40
- * @var integer
41
- */
42
- protected $m_nRequiredLoginInterval;
43
-
44
- /**
45
- * @var integer
46
- */
47
- protected $m_nLastLoginTime;
48
- /**
49
- * @var string
50
- */
51
- protected $nDaysToKeepLog = 1;
52
-
53
- /**
54
- * @param ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions
55
- */
56
- public function __construct( ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions ) {
57
- parent::__construct( $oFeatureOptions, self::TableName );
58
- $this->createTable();
59
- $this->reset();
60
- }
61
-
62
- /**
63
- * Resets the object values to be re-used anew
64
- */
65
- public function reset() {
66
- parent::reset();
67
- self::$sModeFile_LoginThrottled = dirname( __FILE__ ).'/../mode.login_throttled';
68
- }
69
-
70
- /**
71
- *
72
- * @param array $aOptions
73
- */
74
- public function setOptions( &$aOptions ) {
75
- parent::setOptions( $aOptions );
76
- $this->setLoginCooldownInterval();
77
- }
78
-
79
- /**
80
- * @return boolean
81
- */
82
- public function getNeedsEmailHandler() {
83
- return $this->getIsTwoFactorAuthOn();
84
- }
85
-
86
- /**
87
- * @param string $sType can be either 'ip' or 'cookie'. If empty, both are checked looking for either.
88
- * @return bool
89
- */
90
- protected function getIsTwoFactorAuthOn( $sType = '' ) {
91
-
92
- $fIp = $this->getIsOption( 'enable_two_factor_auth_by_ip', 'Y' );
93
- $fCookie = $this->getIsOption( 'enable_two_factor_auth_by_cookie', 'Y' );
94
-
95
- switch( $sType ) {
96
- case 'ip':
97
- return $fIp;
98
- break;
99
- case 'cookie':
100
- return $fCookie;
101
- break;
102
- default:
103
- return $fIp || $fCookie;
104
- break;
105
- }
106
- }
107
-
108
- /**
109
- * @return bool|void
110
- */
111
- public function getIsLogging() {
112
- return $this->getIsOption( 'enable_login_protect_log', 'Y' );
113
- }
114
-
115
- /**
116
- */
117
- public function run() {
118
- parent::run();
119
- $this->loadDataProcessor();
120
- // $this->recreateTable();
121
-
122
- $sRequestMethod = ICWP_WPSF_DataProcessor::ArrayFetch( $_SERVER, 'REQUEST_METHOD' );
123
- $fIsPost = strtolower( empty($sRequestMethod)? '' : $sRequestMethod ) == 'post';
124
-
125
- $aWhitelist = $this->getOption( 'ips_whitelist', array() );
126
- if ( !empty( $aWhitelist ) && $this->isIpOnlist( $aWhitelist, self::GetVisitorIpAddress() ) ) {
127
- return true;
128
- }
129
-
130
- // check for remote posting before anything else.
131
- if ( $fIsPost && $this->getIsOption('enable_prevent_remote_post', 'Y') ) {
132
- add_filter( 'authenticate', array( $this, 'checkRemotePostLogin_Filter' ), 9, 3);
133
- }
134
-
135
- // Add GASP checking to the login form.
136
- if ( $this->getIsOption('enable_login_gasp_check', 'Y') ) {
137
- add_action( 'login_form', array( $this, 'printGaspLoginCheck_Action' ) );
138
- add_action( 'woocommerce_login_form', array( $this, 'printGaspLoginCheck_Action' ) );
139
- add_filter( 'login_form_middle', array( $this, 'printGaspLoginCheck_Filter' ) );
140
- add_filter( 'authenticate', array( $this, 'checkLoginForGasp_Filter' ), 22, 3);
141
- }
142
-
143
- // Do GASP checking if it's a form submit.
144
- if ( $fIsPost && $this->getOption( 'login_limit_interval' ) > 0 ) {
145
- // We give it a priority of 10 so that we can jump in before WordPress does its own validation.
146
- add_filter( 'authenticate', array( $this, 'checkLoginInterval_Filter' ), 10, 3);
147
- }
148
-
149
- // check for Yubikey auth after user is authenticated with WordPress.
150
- if ( $fIsPost && $this->getOption('enable_yubikey') && $this->getIsYubikeyConfigReady() ) {
151
- add_filter( 'wp_authenticate_user', array( $this, 'checkYubikeyOtpAuth_Filter' ) );
152
- add_action( 'login_form', array( $this, 'printYubikeyOtp_Action' ) );
153
- }
154
-
155
- if ( $this->getIsTwoFactorAuthOn() ) {
156
-
157
- // If their click was successful we give them a lovely message
158
- if ( ICWP_WPSF_DataProcessor::FetchGet( 'wpsfuserverified' ) ) {
159
- add_filter( 'login_message', array( $this, 'displayVerifiedUserMessage_Filter' ) );
160
- }
161
-
162
- // Check the current logged-in user every page load.
163
- add_action( 'init', array( $this, 'checkCurrentUserAuth_Action' ) );
164
-
165
- // At this stage (30,3) WordPress has already (20) authenticated the user. So if the login
166
- // is valid, the filter will have a valid WP_User object passed to it.
167
- add_filter( 'authenticate', array( $this, 'checkUserAuthLogin_Filter' ), 30, 3);
168
- }
169
- }
170
-
171
- /**
172
- */
173
- public function printGaspLoginCheck_Action() {
174
- echo $this->getGaspLoginHtml();
175
- }
176
-
177
- /**
178
- * @return string
179
- */
180
- public function printGaspLoginCheck_Filter() {
181
- return $this->getGaspLoginHtml();
182
- }
183
-
184
- /**
185
- * @param $inoUser
186
- * @param $insUsername
187
- * @param $insPassword
188
- * @return mixed
189
- */
190
- public function checkRemotePostLogin_Filter( $inoUser, $insUsername, $insPassword ) {
191
- $this->loadDataProcessor();
192
- $sHttpRef = ICWP_WPSF_DataProcessor::ArrayFetch( $_SERVER, 'HTTP_REFERER' );
193
- $sHttpRef = is_null( $sHttpRef )? '' : $sHttpRef;
194
- if ( empty($sHttpRef) || ( strpos($sHttpRef, home_url()) !== 0 ) ) {
195
- $this->logWarning(
196
- sprintf( _wpsf__('User "%s" attempted to login but the HTTP REFERER was either empty or it was a remote login attempt. Bot Perhaps? HTTP REFERER: "%s".'), $insUsername, $sHttpRef )
197
- );
198
- $this->doStatIncrement( 'login.remotepost.fail' );
199
- wp_die(
200
- _wpsf__( 'Sorry, you must login directly from within the site.' )
201
- .'<br /><a href="http://icwp.io/4n" target="_blank">&rarr;'._wpsf__('More Info').'</a>'
202
- );
203
- }
204
- else {
205
- $this->doStatIncrement( 'login.remotepost.success' );
206
- }
207
- return $inoUser;
208
- }
209
-
210
- /**
211
- * @param $inoUser
212
- * @param $insUsername
213
- * @param $insPassword
214
- * @return WP_Error
215
- */
216
- public function checkLoginForGasp_Filter( $inoUser, $insUsername, $insPassword ) {
217
-
218
- if ( empty( $insUsername ) || is_wp_error( $inoUser ) ) {
219
- return $inoUser;
220
- }
221
- if ( $this->doGaspChecks( $insUsername ) ) {
222
- return $inoUser;
223
- }
224
- //This doesn't actually ever get returned because we die() within doGaspChecks()
225
- return new WP_Error('wpsf_gaspfail', _wpsf__('G.A.S.P. Checking Failed.') );
226
- }
227
-
228
- /**
229
- * Checks whether the current user that is logged-in is authenticated by IP address.
230
- *
231
- * If the user is not found to be valid, they're logged out.
232
- *
233
- * Should be hooked to 'init' so we have is_user_logged_in()
234
- */
235
- public function checkCurrentUserAuth_Action() {
236
-
237
- // User has clicked a link in their email to validate their IP address for login.
238
- if ( ICWP_WPSF_DataProcessor::FetchGet( 'wpsf-action' ) == 'linkauth' ) {
239
- $this->validateUserAuthLink();
240
- }
241
-
242
- if ( is_user_logged_in() ) {
243
- $this->verifyCurrentUser();
244
- }
245
- }
246
-
247
- public function displayVerifiedUserMessage_Filter( $insMessage ) {
248
- $sStyles = 'background-color: #FAFFE8; border: 1px solid #DDDDDD; margin: 8px 0 10px 8px; padding: 16px;';
249
- $insMessage .= '<h3 style="'.$sStyles.'">'._wpsf__('You have successfully verified your identity - you may now login').'</h3>';
250
- return $insMessage;
251
- }
252
-
253
- /**
254
- * Should return false when logging is disabled.
255
- *
256
- * @return false|array - false when logging is disabled, array with log data otherwise
257
- * @see ICWP_WPSF_BaseProcessor::getLogData()
258
- */
259
- public function flushLogData() {
260
-
261
- if ( !$this->getIsLogging() || empty( $this->m_aLogMessages ) ) {
262
- return false;
263
- }
264
-
265
- $this->m_aLog = array(
266
- 'category' => self::LOG_CATEGORY_LOGINPROTECT,
267
- 'messages' => serialize( $this->m_aLogMessages )
268
- );
269
- $this->resetLog();
270
- return $this->m_aLog;
271
- }
272
-
273
- /**
274
- * Checks the link details to ensure all is valid before authorizing the user.
275
- */
276
- public function validateUserAuthLink() {
277
- $this->loadDataProcessor();
278
- // wpsfkey=%s&wpsf-action=%s&username=%s&uniqueid
279
-
280
- if ( ICWP_WPSF_DataProcessor::FetchGet( 'wpsfkey' ) !== $this->oFeatureOptions->getTwoAuthSecretKey() ) {
281
- return false;
282
- }
283
-
284
- $sUsername = ICWP_WPSF_DataProcessor::FetchGet( 'username' );
285
- $sUniqueId = ICWP_WPSF_DataProcessor::FetchGet( 'uniqueid' );
286
- if ( empty( $sUsername ) || empty( $sUniqueId ) ) {
287
- return false;
288
- }
289
-
290
- $aWhere = array(
291
- 'unique_id' => $sUniqueId,
292
- 'wp_username' => $sUsername
293
- );
294
-
295
- $oWp = $this->loadWpFunctionsProcessor();
296
- if ( $this->doMakePendingLoginAuthActive( $aWhere ) ) {
297
- $this->logInfo(
298
- sprintf( _wpsf__('User "%s" verified their identity using Two-Factor Authentication.'), $sUsername )
299
- );
300
- $this->setUserLoggedIn( $sUsername );
301
- $this->doStatIncrement( 'login.twofactor.verified' );
302
- $oWp->redirectToAdmin();
303
- }
304
- else {
305
- $oWp->redirectToHome();
306
- }
307
- }
308
-
309
- // WordPress Hooks and Filters:
310
-
311
- /**
312
- * Should be a filter added to WordPress's "authenticate" filter, but before WordPress performs
313
- * it's own authentication (theirs is priority 30, so we could go in at around 20).
314
- *
315
- * @param null|WP_User|WP_Error $inoUser
316
- * @param string $insUsername
317
- * @param string $insPassword
318
- * @return unknown|WP_Error
319
- */
320
- public function checkLoginInterval_Filter( $inoUser, $insUsername, $insPassword ) {
321
- // No login attempt was made.
322
- if ( empty( $insUsername ) ) {
323
- return $inoUser;
324
- }
325
-
326
- // Is there an interval set?
327
- $this->setLoginCooldownInterval();
328
- $nRequiredLoginInterval = $this->m_nRequiredLoginInterval;
329
- if ( $nRequiredLoginInterval === false || $nRequiredLoginInterval == 0 ) {
330
- return $inoUser;
331
- }
332
-
333
- // Get the last login time (and update it also for the next time)
334
- $this->m_nLastLoginTime = $this->getLastLoginTime();
335
-
336
- if ( empty( $this->m_nLastLoginTime ) || $this->m_nLastLoginTime < 0 ) {
337
- $this->updateLastLoginThrottleTime( self::$nRequestTimestamp );
338
- }
339
-
340
- // If we're outside the interval, let the login process proceed as per normal and
341
- // update our last login time.
342
- $nLoginInterval = self::$nRequestTimestamp - $this->m_nLastLoginTime;
343
- if ( $nLoginInterval > $nRequiredLoginInterval ) {
344
- $this->updateLastLoginThrottleTime( self::$nRequestTimestamp );
345
- $this->doStatIncrement( 'login.cooldown.success' );
346
- return $inoUser;
347
- }
348
-
349
- // At this point someone has attempted to login within the previous login wait interval
350
- // So we remove WordPress's authentication filter and our own user check authentication
351
- // And finally return a WP_Error which will be reflected back to the user.
352
- $this->doStatIncrement( 'login.cooldown.fail' );
353
- remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 ); // wp-includes/user.php
354
- remove_filter( 'authenticate', array( $this, 'checkUserAuthLogin_Filter' ), 30, 3);
355
-
356
- $sErrorString = sprintf( _wpsf__( "Login Cooldown in effect. You must wait %s seconds before attempting to login again." ), ($nRequiredLoginInterval - $nLoginInterval ) );
357
- $oError = new WP_Error( 'wpsf_logininterval', $sErrorString );
358
- return $oError;
359
- }
360
-
361
- /**
362
- * @return int
363
- */
364
- protected function getLastLoginTime() {
365
- $oWpFs = $this->loadFileSystemProcessor();
366
- // Check that there is a login throttle file. If it exists and its modified time is greater than the
367
- // current $this->m_nLastLoginTime it suggests another process has touched the file and updated it
368
- // concurrently. So, we update our $this->m_nEmailThrottleTime accordingly.
369
- if ( $oWpFs->fileAction( 'file_exists', self::$sModeFile_LoginThrottled ) ) {
370
- $nModifiedTime = filemtime( self::$sModeFile_LoginThrottled );
371
- if ( $nModifiedTime > $this->m_nLastLoginTime ) {
372
- $this->m_nLastLoginTime = $nModifiedTime;
373
- }
374
- }
375
- else { }
376
- return $this->m_nLastLoginTime;
377
- }
378
-
379
- /**
380
- * @param $innLastLoginTime
381
- */
382
- public function updateLastLoginThrottleTime( $innLastLoginTime ) {
383
- $oWpFs = $this->loadFileSystemProcessor();
384
- $this->m_nLastLoginTime = $innLastLoginTime;
385
- $oWpFs->fileAction( 'touch', array(self::$sModeFile_LoginThrottled, $innLastLoginTime) );
386
- }
387
-
388
- /**
389
- */
390
- public function printYubikeyOtp_Action() {
391
- $sHtml =
392
- '<p class="yubikey-otp">
393
- <label>%s<br />
394
- <input type="text" name="yubiotp" class="input" value="" size="20" />
395
- </label>
396
- </p>
397
- ';
398
- echo sprintf( $sHtml, '<a href="http://icwp.io/4i" target="_blank">'._wpsf__('Yubikey OTP').'</a>' );
399
- }
400
-
401
- /**
402
- * @param WP_User $inoUser
403
- * @return WP_User|WP_Error
404
- */
405
- public function checkYubikeyOtpAuth_Filter( $inoUser ) {
406
- $oError = new WP_Error();
407
-
408
- // Before anything else we check that a Yubikey pair has been provided for this username (and that there are pairs in the first place!)
409
- $aYubikeyUsernamePairs = $this->getOption('yubikey_unique_keys');
410
- if ( !$this->getIsYubikeyConfigReady() ) { // configuration is clearly not completed yet.
411
- return $inoUser;
412
- }
413
-
414
- $sOneTimePassword = empty( $_POST['yubiotp'] )? '' : trim( $_POST['yubiotp'] );
415
- $sAppId = $this->getOption('yubikey_app_id');
416
- $sApiKey = $this->getOption('yubikey_api_key');
417
-
418
- // check that if we have a list of permitted keys, that the one used is on that list connected with the username.
419
- $sYubikey12 = substr( $sOneTimePassword, 0 , 12 );
420
- $fUsernameFound = false; // if username is never found, it means there's no yubikey specified which means we can bypass this authentication method.
421
- $fFoundMatch = false;
422
- foreach( $aYubikeyUsernamePairs as $aUsernameYubikeyPair ) {
423
- if ( isset( $aUsernameYubikeyPair[$inoUser->user_login] ) ) {
424
- $fUsernameFound = true;
425
- if ( $aUsernameYubikeyPair[$inoUser->user_login] == $sYubikey12 ) {
426
- $fFoundMatch = true;
427
- break;
428
- }
429
- }
430
- }
431
-
432
- // If no yubikey-username pair found for given username, we by-pass Yubikey auth.
433
- if ( !$fUsernameFound ) {
434
- $this->logWarning(
435
- sprintf( _wpsf__('User "%s" logged in without a Yubikey One Time Password because no username-yubikey pair was found for this user.'), $inoUser->user_login )
436
- );
437
- return $inoUser;
438
- }
439
-
440
- // Username was found in the list of key pairs, but the yubikey provided didn't match that username.
441
- if ( !$fFoundMatch ) {
442
- $oError->add(
443
- 'yubikey_not_allowed',
444
- sprintf( _wpsf__( 'ERROR: %s' ), _wpsf__('The Yubikey provided is not on the list of permitted keys for this user.') )
445
- );
446
- $this->logWarning(
447
- sprintf( _wpsf__('User "%s" attempted to login but Yubikey ID used was not in list of authorised keys: "%s".'), $inoUser->user_login, $sYubikey12 )
448
- );
449
- return $oError;
450
- }
451
-
452
- $oFs = $this->loadFileSystemProcessor();
453
-
454
- $sNonce = md5( uniqid( rand() ) );
455
- $sUrl = sprintf( self::YubikeyVerifyApiUrl, $sAppId, $sOneTimePassword, $sNonce );
456
- $sRawYubiRequest = $oFs->getUrlContent( $sUrl );
457
-
458
- // Validate response.
459
- // 1. Check OTP and Nonce
460
- if ( !preg_match( '/otp='.$sOneTimePassword.'/', $sRawYubiRequest, $aMatches )
461
- || !preg_match( '/nonce='.$sNonce.'/', $sRawYubiRequest, $aMatches )
462
- ) {
463
- $oError->add(
464
- 'yubikey_validate_fail',
465
- sprintf( _wpsf__( 'ERROR: %s' ), _wpsf__('The Yubikey authentication was not validated successfully.') )
466
- );
467
- $this->logWarning(
468
- sprintf( _wpsf__('User "%s" attempted to login but Yubikey One Time Password failed to validate due to invalid Yubi API.'), $inoUser->user_login )
469
- );
470
- return $oError;
471
- }
472
-
473
- // Optionally we can check the hash, but since we're using HTTPS, this isn't necessary and adds more PHP requirements
474
-
475
- // 2. Check status directly within response
476
- preg_match( '/status=([a-zA-Z0-9_]+)/', $sRawYubiRequest, $aMatches );
477
- $sStatus = $aMatches[1];
478
-
479
- if ( $sStatus != 'OK' && $sStatus != 'REPLAYED_OTP' ) {
480
- $oError->add(
481
- 'yubikey_validate_fail',
482
- sprintf( _wpsf__( 'ERROR: %s' ), _wpsf__('The Yubikey authentication was not validated successfully.') )
483
- );
484
- $this->logWarning(
485
- sprintf( _wpsf__('User "%s" attempted to login but Yubikey One Time Password failed to validate due to invalid Yubi API response status: %s.'), $inoUser->user_login, $sStatus )
486
- );
487
- return $oError;
488
- }
489
-
490
- $this->logInfo(
491
- sprintf( _wpsf__('User "%s" successfully logged in using a validated Yubikey One Time Password.'), $inoUser->user_login )
492
- );
493
- return $inoUser;
494
- }
495
-
496
- /**
497
- * @return bool
498
- */
499
- protected function getIsYubikeyConfigReady() {
500
- $sAppId = $this->getOption('yubikey_app_id');
501
- $sApiKey = $this->getOption('yubikey_api_key');
502
- $aYubikeyKeys = $this->getOption('yubikey_unique_keys');
503
- return !empty($sAppId) && !empty($sApiKey) && !empty($aYubikeyKeys);
504
- }
505
-
506
- /**
507
- * If $inoUser is a valid WP_User object, then the user logged in correctly.
508
- *
509
- * The flow is as follows:
510
- * 0. If username is empty, there was no login attempt.
511
- * 1. First we determine whether the user's login credentials were valid according to WordPress ($fUserLoginSuccess)
512
- * 2. Then we ask our 2-factor processor whether the current IP address + username combination is authenticated.
513
- * a) if yes, we return the WP_User object and login proceeds as per usual.
514
- * b) if no, we return null, which will send the message back to the user that the login details were invalid.
515
- * 3. If however the user's IP address + username combination is not authenticated, we react differently. We do not want
516
- * to give away whether a login was successful, or even the login username details exist. So:
517
- * a) if the login was a success we add a pending record to the authentication DB for this username+IP address combination and send the appropriate verification email
518
- * b) then, we give back a message saying that if the login was successful, they would have received a verification email. In this way we give nothing away.
519
- * c) note at this stage, if the username was empty, we give back nothing (this happens when wp-login.php is loaded as normal.
520
- *
521
- * @param WP_User|string $inoUser - the docs say the first parameter a string, WP actually gives a WP_User object (or null)
522
- * @param string $insUsername
523
- * @param string $insPassword
524
- * @return WP_Error|WP_User|null - WP_User when the login success AND the IP is authenticated. null when login not successful but IP is valid. WP_Error otherwise.
525
- */
526
- public function checkUserAuthLogin_Filter( $inoUser, $insUsername, $insPassword ) {
527
-
528
- if ( empty( $insUsername ) ) {
529
- return $inoUser;
530
- }
531
-
532
- $fUserLoginSuccess = is_object( $inoUser ) && ( $inoUser instanceof WP_User );
533
-
534
- if ( is_wp_error( $inoUser ) ) {
535
- $aCodes = $inoUser->get_error_codes();
536
- if ( in_array( 'wpsf_logininterval', $aCodes ) ) {
537
- return $inoUser;
538
- }
539
- }
540
- else if ( $fUserLoginSuccess ) {
541
-
542
- if ( !$this->getIsUserLevelSubjectToTwoFactorAuth( $inoUser->user_level ) ) {
543
- return $inoUser;
544
- }
545
-
546
- if ( $this->isUserVerified( $insUsername ) ) {
547
- return $inoUser;
548
- }
549
- else {
550
- // Create a new 2-factor auth pending entry
551
- $aNewAuthData = $this->addNewPendingLoginAuth( $inoUser->user_login );
552
-
553
- // Now send email with authentication link for user.
554
- if ( is_array( $aNewAuthData ) ) {
555
- $this->doStatIncrement( 'login.twofactor.started' );
556
- $fEmailSuccess = $this->sendEmailTwoFactorVerify( $inoUser, $aNewAuthData['ip'], $aNewAuthData['unique_id'] );
557
-
558
- // Failure to send email - log them in.
559
- if ( !$fEmailSuccess && $this->getIsOption( 'enable_two_factor_bypass_on_email_fail', 'Y' ) ) {
560
- $this->doMakePendingLoginAuthActive( $aNewAuthData );
561
- return $inoUser;
562
- }
563
- }
564
- }
565
- }
566
-
567
- $sErrorString = "Login is protected by 2-factor authentication. If your login details were correct, you would have received an email to verify this IP address.";
568
- return new WP_Error( 'wpsf_loginauth', $sErrorString );
569
- }
570
-
571
- /**
572
- * TODO: http://stackoverflow.com/questions/3499104/how-to-know-the-role-of-current-user-in-wordpress
573
- * @param integer $nUserLevel
574
- * @return bool
575
- */
576
- public function getIsUserLevelSubjectToTwoFactorAuth( $nUserLevel ) {
577
-
578
- $aSubjectedUserLevels = $this->getOption( 'two_factor_auth_user_roles' );
579
- if ( empty($aSubjectedUserLevels) || !is_array($aSubjectedUserLevels) ) {
580
- $aSubjectedUserLevels = array( 1, 2, 3, 8 ); // by default all except subscribers!
581
- }
582
-
583
- // see: https://codex.wordpress.org/Roles_and_Capabilities#User_Level_to_Role_Conversion
584
-
585
- // authors, contributors and subscribers
586
- if ( $nUserLevel < 3 && in_array( $nUserLevel, $aSubjectedUserLevels ) ) {
587
- return true;
588
- }
589
- // editors
590
- if ( $nUserLevel >= 3 && $nUserLevel < 8 && in_array( 3, $aSubjectedUserLevels ) ) {
591
- return true;
592
- }
593
- // administrators
594
- if ( $nUserLevel >= 8 && $nUserLevel <= 10 && in_array( 8, $aSubjectedUserLevels ) ) {
595
- return true;
596
- }
597
- return false;
598
- }
599
-
600
- public function getGaspLoginHtml() {
601
-
602
- $sLabel = _wpsf__("I'm a human.");
603
- $sAlert = _wpsf__("Please check the box to show us you're a human.");
604
-
605
- $sUniqElem = 'icwp_wpsf_login_p'.uniqid();
606
-
607
- $sStyles = '
608
- <style>
609
- #'.$sUniqElem.' {
610
- clear:both;
611
- border: 1px solid #888;
612
- padding: 6px 8px 4px 10px;
613
- margin: 0 0px 12px !important;
614
- border-radius: 2px;
615
- background-color: #f9f9f9;
616
- }
617
- #'.$sUniqElem.' input {
618
- margin-right: 5px;
619
- }
620
- </style>
621
- ';
622
-
623
- $sHtml =
624
- $sStyles.
625
- '<p id="'.$sUniqElem.'"></p>
626
- <script type="text/javascript">
627
- var icwp_wpsf_login_p = document.getElementById("'.$sUniqElem.'");
628
- var icwp_wpsf_login_cb = document.createElement("input");
629
- var icwp_wpsf_login_text = document.createTextNode(" '.$sLabel.'");
630
- icwp_wpsf_login_cb.type = "checkbox";
631
- icwp_wpsf_login_cb.id = "'.$this->getGaspCheckboxName().'";
632
- icwp_wpsf_login_cb.name = "'.$this->getGaspCheckboxName().'";
633
- icwp_wpsf_login_p.appendChild( icwp_wpsf_login_cb );
634
- icwp_wpsf_login_p.appendChild( icwp_wpsf_login_text );
635
- var frm = icwp_wpsf_login_cb.form;
636
- frm.onsubmit = icwp_wpsf_login_it;
637
- function icwp_wpsf_login_it(){
638
- if(icwp_wpsf_login_cb.checked != true){
639
- alert("'.$sAlert.'");
640
- return false;
641
- }
642
- return true;
643
- }
644
- </script>
645
- <noscript>'._wpsf__('You MUST enable Javascript to be able to login').'</noscript>
646
- <input type="hidden" id="icwp_wpsf_login_email" name="icwp_wpsf_login_email" value="" />
647
- ';
648
-
649
- return $sHtml;
650
- }
651
-
652
- /**
653
- * @return string
654
- */
655
- public function getGaspCheckboxName() {
656
- return $this->oFeatureOptions->doPluginPrefix( $this->oFeatureOptions->getGaspKey(), '_' );
657
- }
658
-
659
- public function doGaspChecks( $insUsername ) {
660
- if ( !isset( $_POST[ $this->getGaspCheckboxName() ] ) ) {
661
- $this->logWarning(
662
- sprintf( _wpsf__('User "%s" attempted to login but GASP checkbox was not present. Bot Perhaps? IP Address: "%s".'), $insUsername, long2ip(self::$nRequestIp) )
663
- );
664
- $this->doStatIncrement( 'login.gasp.checkbox.fail' );
665
- wp_die( "You must check that box to say you're not a bot." );
666
- return false;
667
- }
668
- else if ( isset( $_POST['icwp_wpsf_login_email'] ) && $_POST['icwp_wpsf_login_email'] !== '' ){
669
- $this->logWarning(
670
- sprintf( _wpsf__('User "%s" attempted to login but they were caught by the GASP honey pot. Bot Perhaps? IP Address: "%s".'), $insUsername, long2ip(self::$nRequestIp) )
671
- );
672
- $this->doStatIncrement( 'login.gasp.honeypot.fail' );
673
- wp_die( _wpsf__('You appear to be a bot - terminating login attempt.') );
674
- return false;
675
- }
676
- return true;
677
- }
678
-
679
- /**
680
- */
681
- public function setLoginCooldownInterval() {
682
- $nInterval = intval( $this->getOption('login_limit_interval', 0) );
683
- $this->m_nRequiredLoginInterval = ( $nInterval < 0 )? 0 : $nInterval;
684
- }
685
-
686
- /**
687
- * @param string $sUsername
688
- * @return boolean
689
- */
690
- public function addNewPendingLoginAuth( $sUsername ) {
691
-
692
- if ( empty( $sUsername ) ) {
693
- return false;
694
- }
695
-
696
- // First set any other pending entries for the given user to be deleted.
697
- $aOldData = array(
698
- 'deleted_at' => self::$nRequestTimestamp,
699
- 'expired_at' => self::$nRequestTimestamp,
700
- );
701
- $aOldWhere = array(
702
- 'pending' => 1,
703
- 'deleted_at' => 0,
704
- 'wp_username' => $sUsername
705
- );
706
- $this->updateRowsFromTable( $aOldData, $aOldWhere );
707
-
708
- // Now add new pending entry
709
- $aNewData = array();
710
- $aNewData[ 'unique_id' ] = uniqid();
711
- $aNewData[ 'ip_long' ] = self::$nRequestIp;
712
- $aNewData[ 'ip' ] = long2ip( self::$nRequestIp );
713
- $aNewData[ 'wp_username' ] = $sUsername;
714
- $aNewData[ 'pending' ] = 1;
715
- $aNewData[ 'created_at' ] = self::$nRequestTimestamp;
716
-
717
- $mResult = $this->insertIntoTable( $aNewData );
718
- if ( $mResult ) {
719
- $this->logInfo(
720
- sprintf( _wpsf__('User "%s" created a pending Two-Factor Authentication for IP Address "%s".'), $sUsername, $aNewData[ 'ip' ] )
721
- );
722
- $mResult = $aNewData;
723
- }
724
- return $mResult;
725
- }
726
-
727
- /**
728
- * Given a unique Id and a corresponding WordPress username, will update the authentication table so that it is active (pending=0).
729
- *
730
- * @param array $inaWhere - unique_id, wp_username
731
- * @return boolean
732
- */
733
- public function doMakePendingLoginAuthActive( $inaWhere ) {
734
-
735
- $aChecks = array( 'unique_id', 'wp_username' );
736
- if ( !$this->validateParameters( $inaWhere, $aChecks ) ) {
737
- return false;
738
- }
739
-
740
- // First set any active, non-pending entries for the given user to be deleted
741
- $this->terminateActiveLoginForUser( $inaWhere['wp_username'] );
742
-
743
- // Now activate the new one.
744
-
745
- // Updates the database
746
- $inaWhere['pending'] = 1;
747
- $inaWhere['deleted_at'] = 0;
748
- $mResult = $this->updateRowsFromTable( array( 'pending' => 0 ), $inaWhere );
749
-
750
- // Set the necessary cookie
751
- $this->setAuthActiveCookie( $inaWhere['unique_id'] );
752
- return $mResult;
753
- }
754
-
755
- /**
756
- * Invalidates all currently active two-factor logins and redirects to admin (->login)
757
- */
758
- public function doTerminateAllVerifiedLogins() {
759
- $this->terminateAllVerifiedLogins();
760
- $oWp = $this->loadWpFunctionsProcessor();
761
- $oWp->redirectToAdmin();
762
- }
763
-
764
- /**
765
- * @param $sUsername
766
- */
767
- protected function setUserLoggedIn( $sUsername ) {
768
- $oWp = $this->loadWpFunctionsProcessor();
769
- $oUser = version_compare( $oWp->getWordpressVersion(), '3.2.2', '<=' )? get_userdatabylogin( $sUsername ) : get_user_by( 'login', $sUsername );
770
-
771
- wp_clear_auth_cookie();
772
- wp_set_current_user ( $oUser->ID, $oUser->user_login );
773
- wp_set_auth_cookie ( $oUser->ID, true );
774
- do_action( 'wp_login', $oUser->user_login );
775
- }
776
-
777
- /**
778
- * Given a username will soft-delete any currently active two-factor authentication.
779
- *
780
- * @param $sUsername
781
- */
782
- protected function terminateActiveLoginForUser( $sUsername ) {
783
- $sQuery = "
784
- UPDATE `%s`
785
- SET `deleted_at` = '%s',
786
- `expired_at` = '%s'
787
- WHERE
788
- `wp_username` = '%s'
789
- AND `deleted_at` = '0'
790
- AND `pending` = '0'
791
- ";
792
- $sQuery = sprintf( $sQuery,
793
- $this->getTableName(),
794
- self::$nRequestTimestamp,
795
- self::$nRequestTimestamp,
796
- esc_sql( $sUsername )
797
- );
798
- $this->doSql( $sQuery );
799
- }
800
-
801
- /**
802
- *
803
- */
804
- protected function terminateAllVerifiedLogins() {
805
- $sQuery = "
806
- UPDATE `%s`
807
- SET `deleted_at` = '%s',
808
- `expired_at` = '%s'
809
- WHERE
810
- `deleted_at` = '0'
811
- AND `pending` = '0'
812
- ";
813
- $sQuery = sprintf( $sQuery,
814
- $this->getTableName(),
815
- self::$nRequestTimestamp,
816
- self::$nRequestTimestamp
817
- );
818
- return $this->doSql( $sQuery );
819
- }
820
-
821
- /**
822
- * @param $insUniqueId
823
- */
824
- public function setAuthActiveCookie( $insUniqueId ) {
825
- $nWeek = defined( 'WEEK_IN_SECONDS' )? WEEK_IN_SECONDS : 24*60*60;
826
- setcookie( self::AuthActiveCookie, $insUniqueId, self::$nRequestTimestamp+$nWeek, COOKIEPATH, COOKIE_DOMAIN, false );
827
- }
828
-
829
- /**
830
- * Checks whether a given user is authenticated.
831
- *
832
- * @param string $sUsername
833
- * @return boolean
834
- */
835
- public function isUserVerified( $sUsername ) {
836
-
837
- $sQuery = "
838
- SELECT *
839
- FROM `%s`
840
- WHERE
841
- `wp_username` = '%s'
842
- AND `pending` = '0'
843
- AND `deleted_at` = '0'
844
- AND `expired_at` = '0'
845
- ";
846
-
847
- $sQuery = sprintf( $sQuery,
848
- $this->getTableName(),
849
- $sUsername
850
- );
851
-
852
- $mResult = $this->selectCustomFromTable( $sQuery );
853
-
854
- if ( is_array( $mResult ) && count( $mResult ) == 1 ) {
855
- // Now we test based on which types of 2-factor auth is enabled
856
- $fVerified = true;
857
- $aUserAuthData = $mResult[0];
858
- if ( $this->getIsTwoFactorAuthOn('ip') && ( self::$nRequestIp != $aUserAuthData['ip_long'] ) ) {
859
- $fVerified = false;
860
- }
861
- if ( $fVerified && $this->getIsTwoFactorAuthOn('cookie') && !$this->isAuthCookieValid($aUserAuthData['unique_id']) ) {
862
- $fVerified = false;
863
- }
864
- return $fVerified;
865
- }
866
- else {
867
- $this->logWarning(
868
- sprintf( _wpsf__('User "%s" was found to be un-verified at the given IP Address "%s"'), $sUsername, long2ip( self::$nRequestIp ) )
869
- );
870
- return false;
871
- }
872
- }
873
-
874
- /**
875
- * @param $sUniqueId
876
- * @return bool
877
- */
878
- protected function isAuthCookieValid( $sUniqueId ) {
879
- $this->loadDataProcessor();
880
- return ICWP_WPSF_DataProcessor::FetchCookie( self::AuthActiveCookie ) == $sUniqueId;
881
- }
882
-
883
- /**
884
- * If it cannot verify current user, will forcefully log them out and redirect to login
885
- */
886
- public function verifyCurrentUser() {
887
- $oUser = wp_get_current_user();
888
- if ( is_object( $oUser ) && $oUser instanceof WP_User ) {
889
-
890
- if ( $this->getIsUserLevelSubjectToTwoFactorAuth( $oUser->user_level ) && !$this->isUserVerified( $oUser->user_login ) ) {
891
- $this->logWarning(
892
- sprintf( _wpsf__('User "%s" was forcefully logged out as they are not verified by either cookie or IP address (or both).'), $oUser->user_login )
893
- );
894
- $this->doStatIncrement( 'login.userverify.fail' );
895
- wp_logout();
896
- $oWp = $this->loadWpFunctionsProcessor();
897
- $oWp->redirectToLogin();
898
- }
899
- }
900
- }
901
-
902
- /**
903
- * Given the necessary components, creates the 2-factor verification link for giving to the user.
904
- *
905
- * @param string $sUser
906
- * @param string $sUniqueId
907
- * @return string
908
- */
909
- protected function generateTwoFactorVerifyLink( $sUser, $sUniqueId ) {
910
- $sSiteUrl = home_url() . '?wpsfkey=%s&wpsf-action=%s&username=%s&uniqueid=%s';
911
- $sAction = 'linkauth';
912
- return sprintf( $sSiteUrl, $this->oFeatureOptions->getTwoAuthSecretKey(), $sAction, $sUser, $sUniqueId );
913
- }
914
-
915
- /**
916
- * @param WP_User $inoUser
917
- * @param string $insIpAddress
918
- * @param string $insUniqueId
919
- * @return boolean
920
- */
921
- public function sendEmailTwoFactorVerify( WP_User $inoUser, $insIpAddress, $insUniqueId ) {
922
-
923
- $sEmail = $inoUser->user_email;
924
- $sAuthLink = $this->generateTwoFactorVerifyLink( $inoUser->user_login, $insUniqueId );
925
-
926
- $aMessage = array(
927
- _wpsf__('You, or someone pretending to be you, just attempted to login into your WordPress site.'),
928
- _wpsf__('The IP Address / Cookie from which they tried to login is not currently verified.'),
929
- _wpsf__('To validate this user, click the following link and then attempt to login again.'),
930
- sprintf( _wpsf__('IP Address: %s'), $insIpAddress ),
931
- sprintf( _wpsf__('Authentication Link: %s'), $sAuthLink ),
932
- );
933
- $sEmailSubject = sprintf( _wpsf__('Two-Factor Login Verification for: %s'), home_url() );
934
-
935
- // add filters to email sending (for now only Mandrill)
936
- add_filter( 'mandrill_payload', array($this, 'customiseMandrill') );
937
-
938
- $fResult = $this->getEmailProcessor()->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
939
- if ( $fResult ) {
940
- $this->logInfo(
941
- sprintf( _wpsf__('User "%s" was sent an email to verify their Identity using Two-Factor Login Auth for IP address "%s".'), $inoUser->user_login, $insIpAddress )
942
- );
943
- }
944
- else {
945
- $this->logCritical(
946
- sprintf( _wpsf__('Tried to send User "%s" email to verify their Identity using Two-Factor Login Auth for IP Address "%s", but email sending failed.'), $inoUser->user_login, $insIpAddress )
947
- );
948
- }
949
- return $fResult;
950
- }
951
-
952
- /**
953
- * @param array $aMessage
954
- * @return array
955
- */
956
- public function customiseMandrill( $aMessage ) {
957
- if ( empty( $aMessage['text'] ) ) {
958
- $aMessage['text'] = $aMessage['html'];
959
- }
960
- return $aMessage;
961
- }
962
-
963
- public function createTable() {
964
-
965
- // Set up login processor table
966
- $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
967
- `id` int(11) NOT NULL AUTO_INCREMENT,
968
- `unique_id` varchar(20) NOT NULL DEFAULT '',
969
- `wp_username` varchar(255) NOT NULL DEFAULT '',
970
- `ip` varchar(20) NOT NULL DEFAULT '',
971
- `ip_long` bigint(20) NOT NULL DEFAULT '0',
972
- `pending` int(1) NOT NULL DEFAULT '0',
973
- `created_at` int(15) NOT NULL DEFAULT '0',
974
- `deleted_at` int(15) NOT NULL DEFAULT '0',
975
- `expired_at` int(15) NOT NULL DEFAULT '0',
976
- PRIMARY KEY (`id`)
977
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
978
- $sSqlTables = sprintf( $sSqlTables, $this->getTableName() );
979
- $mResult = $this->doSql( $sSqlTables );
980
- }
981
-
982
- /**
983
- * Assumes that unique_id AND wp_username have been set correctly in the data array (no checking done).
984
- *
985
- * @param array $inaData
986
- * @return array
987
- */
988
- protected function getLoginAuthData( $inaData ) {
989
-
990
- $sQuery = "SELECT * FROM %s WHERE `unique_id` = `%s` AND `wp_username` = %s";
991
- $sQuery = sprintf( $sQuery, $this->getTableName(), $inaData['unique_id'], $inaData['wp_username'] );
992
- return $this->selectRowFromTable( $sQuery );
993
- }
994
-
995
- /**
996
- * This is hooked into a cron in the base class and overrides the parent method.
997
- *
998
- * It'll delete everything older than 24hrs.
999
- */
1000
- public function cleanupDatabase() {
1001
- if ( !$this->getTableExists() ) {
1002
- return;
1003
- }
1004
- $nTimeStamp = self::$nRequestTimestamp - (DAY_IN_SECONDS * $this->nDaysToKeepLog);
1005
- $this->deleteAllRowsOlderThan( $nTimeStamp );
1006
- }
1007
-
1008
- /**
1009
- * @param $nTimeStamp
1010
- */
1011
- protected function deleteAllRowsOlderThan( $nTimeStamp ) {
1012
- $sQuery = "
1013
- DELETE from `%s`
1014
- WHERE
1015
- `created_at` < '%s'
1016
- AND `pending` = '1'
1017
- ";
1018
- $sQuery = sprintf( $sQuery,
1019
- $this->getTableName(),
1020
- esc_sql( $nTimeStamp )
1021
- );
1022
- $this->doSql( $sQuery );
1023
- }
1024
-
1025
- }
1026
- endif;
1027
-
1028
- if ( !class_exists('ICWP_WPSF_LoginProtectProcessor') ):
1029
- class ICWP_WPSF_LoginProtectProcessor extends ICWP_LoginProtectProcessor_V3 { }
1030
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/icwp-processor-loginprotect_cooldown.php ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_LoginProtect_Cooldown') ):
21
+
22
+ class ICWP_WPSF_Processor_LoginProtect_Cooldown extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_LoginProtect
26
+ */
27
+ protected $oFeatureOptions;
28
+
29
+ /**
30
+ */
31
+ public function __construct( ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions ) {
32
+ parent::__construct( $oFeatureOptions );
33
+ }
34
+
35
+ /**
36
+ * @return int
37
+ */
38
+ public function getLoginCooldownInterval() {
39
+ return $this->getOption( 'login_limit_interval' );
40
+ }
41
+
42
+ /**
43
+ * @return int
44
+ */
45
+ public function getLastLoginTime() {
46
+ $sFilePath = $this->oFeatureOptions->getLastLoginTimeFilePath();
47
+ $oWpFs = $this->loadFileSystemProcessor();
48
+ $nModifiedFileTime = ( $oWpFs->exists( $sFilePath ) ) ? filemtime( $sFilePath ) : 0;
49
+ return max( $nModifiedFileTime, $this->getOption( 'last_login_time' ) );
50
+ }
51
+
52
+ /**
53
+ *
54
+ */
55
+ protected function updateLastLoginTime() {
56
+ $oDp = $this->loadDataProcessor();
57
+ $this->oFeatureOptions->setOpt( 'last_login_time', $oDp->GetRequestTime() );
58
+ $oWpFs = $this->loadFileSystemProcessor();
59
+ $oWpFs->touch( $this->oFeatureOptions->getLastLoginTimeFilePath(), $oDp->GetRequestTime() );
60
+ }
61
+
62
+ /**
63
+ */
64
+ public function run() {
65
+ // We give it a priority of 10 so that we can jump in before WordPress does its own validation.
66
+ add_filter( 'authenticate', array( $this, 'checkLoginInterval' ), 10, 3 );
67
+ }
68
+
69
+ /**
70
+ * Should be a filter added to WordPress's "authenticate" filter, but before WordPress performs
71
+ * it's own authentication (theirs is priority 30, so we could go in at around 20).
72
+ *
73
+ * @param null|WP_User|WP_Error $oUser
74
+ * @param string $sUsername
75
+ * @param string $sPassword
76
+ * @return unknown|WP_Error
77
+ */
78
+ public function checkLoginInterval( $oUser, $sUsername, $sPassword ) {
79
+ // No login attempt was made and we do nothing
80
+ if ( empty( $sUsername ) ) {
81
+ return $oUser;
82
+ }
83
+
84
+ // Is there an interval set?
85
+ $nRequiredLoginInterval = $this->getLoginCooldownInterval();
86
+ if ( empty( $nRequiredLoginInterval ) || $nRequiredLoginInterval < 0 ) {
87
+ return $oUser;
88
+ }
89
+
90
+ // If we're outside the interval, let the login process proceed as per normal and
91
+ // update our last login time.
92
+ $oDp = $this->loadDataProcessor();
93
+ $nCurrentLoginInterval = $oDp->GetRequestTime() - $this->getLastLoginTime();
94
+ if ( $nCurrentLoginInterval > $nRequiredLoginInterval ) {
95
+ $this->updateLastLoginTime();
96
+ $this->doStatIncrement( 'login.cooldown.success' );
97
+ return $oUser;
98
+ }
99
+
100
+ // At this point someone has attempted to login within the previous login wait interval
101
+ // So we remove WordPress's authentication filter and our own user check authentication
102
+ // And finally return a WP_Error which will be reflected back to the user.
103
+ $this->doStatIncrement( 'login.cooldown.fail' );
104
+ remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 ); // wp-includes/user.php
105
+
106
+ $sErrorString = sprintf( _wpsf__( "Login Cooldown in effect. You must wait %s seconds before attempting to login again." ), ($nRequiredLoginInterval - $nCurrentLoginInterval ) );
107
+ $oError = new WP_Error( 'wpsf_logininterval', $sErrorString );
108
+ return $oError;
109
+ }
110
+ }
111
+ endif;
src/icwp-processor-loginprotect_gasp.php ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_LoginProtect_Gasp') ):
21
+
22
+ class ICWP_WPSF_Processor_LoginProtect_Gasp extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_LoginProtect
26
+ */
27
+ protected $oFeatureOptions;
28
+
29
+ /**
30
+ */
31
+ public function __construct( ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions ) {
32
+ $this->oFeatureOptions = $oFeatureOptions;
33
+ }
34
+
35
+ /**
36
+ */
37
+ public function run() {
38
+ // Add GASP checking to the login form.
39
+ add_action( 'login_form', array( $this, 'printGaspLoginCheck_Action' ) );
40
+ add_action( 'woocommerce_login_form', array( $this, 'printGaspLoginCheck_Action' ) );
41
+ add_filter( 'login_form_middle', array( $this, 'printGaspLoginCheck_Filter' ) );
42
+ add_filter( 'authenticate', array( $this, 'checkLoginForGasp_Filter' ), 22, 3);
43
+ }
44
+
45
+ /**
46
+ */
47
+ public function printGaspLoginCheck_Action() {
48
+ echo $this->getGaspLoginHtml();
49
+ }
50
+
51
+ /**
52
+ * @return string
53
+ */
54
+ public function printGaspLoginCheck_Filter() {
55
+ return $this->getGaspLoginHtml();
56
+ }
57
+
58
+ /**
59
+ * @param $oUser
60
+ * @param $sUsername
61
+ * @param $insPassword
62
+ * @return WP_Error
63
+ */
64
+ public function checkLoginForGasp_Filter( $oUser, $sUsername, $insPassword ) {
65
+
66
+ if ( empty( $sUsername ) || is_wp_error( $oUser ) ) {
67
+ return $oUser;
68
+ }
69
+ if ( $this->doGaspChecks( $sUsername ) ) {
70
+ return $oUser;
71
+ }
72
+ //This doesn't actually ever get returned because we die() within doGaspChecks()
73
+ return new WP_Error('wpsf_gaspfail', _wpsf__('G.A.S.P. Checking Failed.') );
74
+ }
75
+
76
+ public function getGaspLoginHtml() {
77
+
78
+ $sLabel = _wpsf__("I'm a human.");
79
+ $sAlert = _wpsf__("Please check the box to show us you're a human.");
80
+
81
+ $sUniqElem = 'icwp_wpsf_login_p'.uniqid();
82
+
83
+ $sStyles = '
84
+ <style>
85
+ #'.$sUniqElem.' {
86
+ clear:both;
87
+ border: 1px solid #888;
88
+ padding: 6px 8px 4px 10px;
89
+ margin: 0 0px 12px !important;
90
+ border-radius: 2px;
91
+ background-color: #f9f9f9;
92
+ }
93
+ #'.$sUniqElem.' input {
94
+ margin-right: 5px;
95
+ }
96
+ </style>
97
+ ';
98
+
99
+ $sHtml =
100
+ $sStyles.
101
+ '<p id="'.$sUniqElem.'"></p>
102
+ <script type="text/javascript">
103
+ var icwp_wpsf_login_p = document.getElementById("'.$sUniqElem.'");
104
+ var icwp_wpsf_login_cb = document.createElement("input");
105
+ var icwp_wpsf_login_text = document.createTextNode(" '.$sLabel.'");
106
+ icwp_wpsf_login_cb.type = "checkbox";
107
+ icwp_wpsf_login_cb.id = "'.$this->getGaspCheckboxName().'";
108
+ icwp_wpsf_login_cb.name = "'.$this->getGaspCheckboxName().'";
109
+ icwp_wpsf_login_p.appendChild( icwp_wpsf_login_cb );
110
+ icwp_wpsf_login_p.appendChild( icwp_wpsf_login_text );
111
+ var frm = icwp_wpsf_login_cb.form;
112
+ frm.onsubmit = icwp_wpsf_login_it;
113
+ function icwp_wpsf_login_it(){
114
+ if(icwp_wpsf_login_cb.checked != true){
115
+ alert("'.$sAlert.'");
116
+ return false;
117
+ }
118
+ return true;
119
+ }
120
+ </script>
121
+ <noscript>'._wpsf__('You MUST enable Javascript to be able to login').'</noscript>
122
+ <input type="hidden" id="icwp_wpsf_login_email" name="icwp_wpsf_login_email" value="" />
123
+ ';
124
+
125
+ return $sHtml;
126
+ }
127
+
128
+ /**
129
+ * @return string
130
+ */
131
+ public function getGaspCheckboxName() {
132
+ return $this->oFeatureOptions->doPluginPrefix( $this->oFeatureOptions->getGaspKey() );
133
+ }
134
+
135
+ /**
136
+ * @param $sUsername
137
+ * @return bool
138
+ */
139
+ public function doGaspChecks( $sUsername ) {
140
+ $oDp = $this->loadDataProcessor();
141
+ $sGaspCheckBox = $oDp->FetchPost( $this->getGaspCheckboxName() );
142
+ $sHoney = $oDp->FetchPost( 'icwp_wpsf_login_email' );
143
+
144
+ if ( empty( $sGaspCheckBox ) ) {
145
+ $this->logWarning(
146
+ sprintf( _wpsf__('User "%s" attempted to login but GASP checkbox was not present. Bot Perhaps? IP Address: "%s".'),
147
+ $sUsername,
148
+ $oDp->FetchPost( false )
149
+ )
150
+ );
151
+ $this->doStatIncrement( 'login.gasp.checkbox.fail' );
152
+ wp_die( "You must check that box to say you're not a bot." );
153
+ return false;
154
+ }
155
+ else if ( !empty( $sHoney ) ) {
156
+ $this->logWarning(
157
+ sprintf( _wpsf__('User "%s" attempted to login but they were caught by the GASP honey pot. Bot Perhaps? IP Address: "%s".'),
158
+ $sUsername,
159
+ $oDp->FetchPost( false )
160
+ )
161
+ );
162
+ $this->doStatIncrement( 'login.gasp.honeypot.fail' );
163
+ wp_die( _wpsf__('You appear to be a bot - terminating login attempt.') );
164
+ return false;
165
+ }
166
+ return true;
167
+ }
168
+ }
169
+ endif;
src/icwp-processor-loginprotect_twofactorauth.php ADDED
@@ -0,0 +1,548 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-basedb.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth') ):
21
+
22
+ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_BaseDbProcessor {
23
+
24
+ const AuthActiveCookie = 'wpsf_auth';
25
+
26
+ /**
27
+ * @var ICWP_WPSF_FeatureHandler_LoginProtect
28
+ */
29
+ protected $oFeatureOptions;
30
+ /**
31
+ * @var string
32
+ */
33
+ protected $nDaysToKeepLog = 1;
34
+
35
+ /**
36
+ * @param ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions
37
+ */
38
+ public function __construct( ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions ) {
39
+ parent::__construct( $oFeatureOptions, $oFeatureOptions->getTwoFactorAuthTableName() );
40
+ }
41
+
42
+ /**
43
+ */
44
+ public function run() {
45
+ parent::run();
46
+ $oDp = $this->loadDataProcessor();
47
+
48
+ // User has clicked a link in their email to validate their IP address for login.
49
+ if ( $oDp->FetchGet( 'wpsf-action' ) == 'linkauth' ) {
50
+ add_action( 'init', array( $this, 'validateUserAuthLink' ), 10 );
51
+ }
52
+
53
+ // Check the current logged-in user every page load.
54
+ add_action( 'init', array( $this, 'checkCurrentUserAuth' ), 11 );
55
+
56
+ // At this stage (30,3) WordPress has already (20) authenticated the user. So if the login
57
+ // is valid, the filter will have a valid WP_User object passed to it.
58
+ add_filter( 'authenticate', array( $this, 'doUserTwoFactorAuth' ), 30, 3);
59
+ }
60
+
61
+ /**
62
+ * Checks whether the current user that is logged-in is authenticated by IP address.
63
+ *
64
+ * If the user is not found to be valid, they're logged out.
65
+ *
66
+ * Should be hooked to 'init' so we have is_user_logged_in()
67
+ */
68
+ public function checkCurrentUserAuth() {
69
+
70
+ if ( is_user_logged_in() ) {
71
+
72
+ $oWp = $this->loadWpFunctionsProcessor();
73
+ $oUser = $oWp->getCurrentWpUser();
74
+ if ( !is_null( $oUser ) ) {
75
+
76
+ if ( $this->getIsUserLevelSubjectToTwoFactorAuth( $oUser->user_level ) && !$this->getUserHasValidAuth( $oUser ) ) {
77
+
78
+ $this->logWarning(
79
+ sprintf( _wpsf__('User "%s" was forcefully logged out as they are not verified by either cookie or IP address (or both).'), $oUser->user_login )
80
+ );
81
+
82
+ $this->doStatIncrement( 'login.userverify.fail' );
83
+ $oWp->forceUserRelogin( array( 'wpsf-forcelogout' => 6 ) );
84
+ }
85
+ }
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Checks whether a given user is authenticated.
91
+ *
92
+ * @param WP_User $oUser
93
+ * @return boolean
94
+ */
95
+ public function getUserHasValidAuth( $oUser ) {
96
+
97
+ $fVerified = false;
98
+ $aUserAuthData = $this->query_GetActiveAuthForUser( $oUser );
99
+
100
+ if ( !is_null( $aUserAuthData ) ) {
101
+
102
+ // Now we test based on which types of 2-factor auth is enabled
103
+ $fVerified = true;
104
+ if ( $this->oFeatureOptions->getIsTwoFactorAuthOn('ip') && ( self::$nRequestIp != $aUserAuthData['ip_long'] ) ) {
105
+ $fVerified = false;
106
+ }
107
+
108
+ if ( $fVerified && $this->oFeatureOptions->getIsTwoFactorAuthOn('cookie') && !$this->getIsAuthCookieValid( $aUserAuthData['unique_id'] ) ) {
109
+ $fVerified = false;
110
+ }
111
+ }
112
+
113
+ if ( !$fVerified ) {
114
+ $this->logWarning(
115
+ sprintf( _wpsf__('User "%s" was found to be un-verified at the given IP Address "%s"'), $oUser->user_login, long2ip( self::$nRequestIp ) )
116
+ );
117
+ }
118
+
119
+ return $fVerified;
120
+ }
121
+
122
+ /**
123
+ * Checks the link details to ensure all is valid before authorizing the user.
124
+ */
125
+ public function validateUserAuthLink() {
126
+ $oDp = $this->loadDataProcessor();
127
+ // wpsfkey=%s&wpsf-action=%s&username=%s&uniqueid
128
+
129
+ if ( $oDp->FetchGet( 'wpsfkey' ) !== $this->oFeatureOptions->getTwoAuthSecretKey() ) {
130
+ return false;
131
+ }
132
+
133
+ $sUsername = $oDp->FetchGet( 'username' );
134
+ $sUniqueId = $oDp->FetchGet( 'uniqueid' );
135
+
136
+ if ( empty( $sUsername ) || empty( $sUniqueId ) ) {
137
+ return false;
138
+ }
139
+
140
+ $oWp = $this->loadWpFunctionsProcessor();
141
+ if ( $this->setLoginAuthActive( $sUniqueId, $sUsername ) ) {
142
+ $this->logInfo(
143
+ sprintf( _wpsf__('User "%s" verified their identity using Two-Factor Authentication.'), $sUsername )
144
+ );
145
+ $this->doStatIncrement( 'login.twofactor.verified' );
146
+ $oWp->setUserLoggedIn( $sUsername );
147
+ $oWp->redirectToAdmin();
148
+ }
149
+ else {
150
+ $oWp->redirectToLogin();
151
+ }
152
+ }
153
+
154
+ /**
155
+ * If $inoUser is a valid WP_User object, then the user logged in correctly.
156
+ *
157
+ * The flow is as follows:
158
+ * 0. If username is empty, there was no login attempt.
159
+ * 1. First we determine whether the user's login credentials were valid according to WordPress ($fUserLoginSuccess)
160
+ * 2. Then we ask our 2-factor processor whether the current IP address + username combination is authenticated.
161
+ * a) if yes, we return the WP_User object and login proceeds as per usual.
162
+ * b) if no, we return null, which will send the message back to the user that the login details were invalid.
163
+ * 3. If however the user's IP address + username combination is not authenticated, we react differently. We do not want
164
+ * to give away whether a login was successful, or even the login username details exist. So:
165
+ * a) if the login was a success we add a pending record to the authentication DB for this username+IP address combination and send the appropriate verification email
166
+ * b) then, we give back a message saying that if the login was successful, they would have received a verification email. In this way we give nothing away.
167
+ * c) note at this stage, if the username was empty, we give back nothing (this happens when wp-login.php is loaded as normal.
168
+ *
169
+ * @param WP_User|string $oUser - the docs say the first parameter a string, WP actually gives a WP_User object (or null)
170
+ * @param string $sUsername
171
+ * @param string $sPassword
172
+ * @return WP_Error|WP_User|null - WP_User when the login success AND the IP is authenticated. null when login not successful but IP is valid. WP_Error otherwise.
173
+ */
174
+ public function doUserTwoFactorAuth( $oUser, $sUsername, $sPassword ) {
175
+
176
+ if ( empty( $sUsername ) ) {
177
+ return $oUser;
178
+ }
179
+
180
+ $fUserLoginSuccess = is_object( $oUser ) && ( $oUser instanceof WP_User );
181
+
182
+ if ( $fUserLoginSuccess ) {
183
+
184
+ if ( !$this->getIsUserLevelSubjectToTwoFactorAuth( $oUser->user_level ) ) {
185
+ return $oUser;
186
+ }
187
+ if ( $this->getUserHasValidAuth( $oUser ) ) {
188
+ return $oUser;
189
+ }
190
+
191
+ // Create a new 2-factor auth pending entry
192
+ $aNewAuthData = $this->query_DoCreatePendingLoginAuth( $oUser->user_login );
193
+
194
+ // Now send email with authentication link for user.
195
+ if ( is_array( $aNewAuthData ) ) {
196
+ $this->doStatIncrement( 'login.twofactor.started' );
197
+ $fEmailSuccess = $this->sendEmailTwoFactorVerify( $oUser, $aNewAuthData['ip'], $aNewAuthData['unique_id'] );
198
+
199
+ // Failure to send email - log them in.
200
+ if ( !$fEmailSuccess && $this->getIsOption( 'enable_two_factor_bypass_on_email_fail', 'Y' ) ) {
201
+ $this->setLoginAuthActive( $aNewAuthData['unique_id'], $aNewAuthData['wp_username'] );
202
+ return $oUser;
203
+ }
204
+ }
205
+ }
206
+
207
+ // We default to returning a login cooldown error if that's in place.
208
+ if ( is_wp_error( $oUser ) ) {
209
+ $aCodes = $oUser->get_error_codes();
210
+ if ( in_array( 'wpsf_logininterval', $aCodes ) ) {
211
+ return $oUser;
212
+ }
213
+ }
214
+
215
+ $sErrorString = _wpsf__( "Login is protected by 2-factor authentication." )
216
+ .' '._wpsf__( "If your login details were correct, you will have received an email to complete the login process." ) ;
217
+ return new WP_Error( 'wpsf_loginauth', $sErrorString );
218
+ }
219
+
220
+ /**
221
+ * @param string $sUniqueId
222
+ * @param string $sUsername
223
+ * @return boolean
224
+ */
225
+ public function setLoginAuthActive( $sUniqueId, $sUsername ) {
226
+ // 1. Terminate old entries
227
+ $this->query_DoTerminateActiveLoginForUser( $sUsername );
228
+
229
+ // 2. Authenticate new entry
230
+ $aWhere = array(
231
+ 'unique_id' => $sUniqueId,
232
+ 'wp_username' => $sUsername
233
+ );
234
+ $this->query_DoMakePendingLoginAuthActive( $aWhere );
235
+
236
+ // 3. Set Auth Cookie
237
+ $this->setAuthActiveCookie( $sUniqueId );
238
+
239
+ return true;
240
+ }
241
+
242
+ /**
243
+ * TODO: http://stackoverflow.com/questions/3499104/how-to-know-the-role-of-current-user-in-wordpress
244
+ * @param integer $nUserLevel
245
+ * @return bool
246
+ */
247
+ protected function getIsUserLevelSubjectToTwoFactorAuth( $nUserLevel ) {
248
+
249
+ $aSubjectedUserLevels = $this->getOption( 'two_factor_auth_user_roles' );
250
+ if ( empty($aSubjectedUserLevels) || !is_array($aSubjectedUserLevels) ) {
251
+ $aSubjectedUserLevels = array( 1, 2, 3, 8 ); // by default all roles except subscribers!
252
+ }
253
+
254
+ // see: https://codex.wordpress.org/Roles_and_Capabilities#User_Level_to_Role_Conversion
255
+
256
+ // authors, contributors and subscribers
257
+ if ( $nUserLevel < 3 && in_array( $nUserLevel, $aSubjectedUserLevels ) ) {
258
+ return true;
259
+ }
260
+ // editors
261
+ if ( $nUserLevel >= 3 && $nUserLevel < 8 && in_array( 3, $aSubjectedUserLevels ) ) {
262
+ return true;
263
+ }
264
+ // administrators
265
+ if ( $nUserLevel >= 8 && $nUserLevel <= 10 && in_array( 8, $aSubjectedUserLevels ) ) {
266
+ return true;
267
+ }
268
+ return false;
269
+ }
270
+
271
+ /**
272
+ * @param string $sUsername
273
+ * @return boolean
274
+ */
275
+ protected function query_DoCreatePendingLoginAuth( $sUsername ) {
276
+
277
+ if ( empty( $sUsername ) ) {
278
+ return false;
279
+ }
280
+
281
+ // First set any other pending entries for the given user to be deleted.
282
+ $aSetDeleted = array(
283
+ 'deleted_at' => self::$nRequestTimestamp,
284
+ 'expired_at' => self::$nRequestTimestamp,
285
+ );
286
+ $aOldPendingAuth = array(
287
+ 'pending' => 1,
288
+ 'deleted_at' => 0,
289
+ 'wp_username' => $sUsername
290
+ );
291
+ $this->updateRowsFromTable( $aSetDeleted, $aOldPendingAuth );
292
+
293
+ // Now add new pending entry
294
+ $aNewData = array();
295
+ $aNewData[ 'unique_id' ] = uniqid();
296
+ $aNewData[ 'ip_long' ] = self::$nRequestIp;
297
+ $aNewData[ 'ip' ] = long2ip( self::$nRequestIp );
298
+ $aNewData[ 'wp_username' ] = $sUsername;
299
+ $aNewData[ 'pending' ] = 1;
300
+ $aNewData[ 'created_at' ] = self::$nRequestTimestamp;
301
+
302
+ $mResult = $this->insertIntoTable( $aNewData );
303
+ return $mResult ? $aNewData : $mResult;
304
+ }
305
+
306
+ /**
307
+ * Given a unique ID and a corresponding WordPress username, will update the authentication table so that it is active (pending=0).
308
+ *
309
+ * @param array $aWhere - unique_id, wp_username
310
+ * @return boolean
311
+ */
312
+ public function query_DoMakePendingLoginAuthActive( $aWhere ) {
313
+
314
+ $aChecks = array( 'unique_id', 'wp_username' );
315
+ if ( !$this->validateParameters( $aWhere, $aChecks ) ) {
316
+ return false;
317
+ }
318
+
319
+ // Activate the new one.
320
+ $aWhere['pending'] = 1;
321
+ $aWhere['deleted_at'] = 0;
322
+ $mResult = $this->updateRowsFromTable( array( 'pending' => 0 ), $aWhere );
323
+ return $mResult;
324
+ }
325
+
326
+ /**
327
+ * Invalidates all currently active two-factor logins and redirects to admin (->login)
328
+ */
329
+ public function doTerminateAllVerifiedLogins() {
330
+ $this->query_DoTerminateAllVerifiedLogins();
331
+ $oWp = $this->loadWpFunctionsProcessor();
332
+ $oWp->redirectToAdmin();
333
+ }
334
+
335
+ /**
336
+ * Given a username will soft-delete any currently active two-factor authentication.
337
+ *
338
+ * @param $sUsername
339
+ */
340
+ protected function query_DoTerminateActiveLoginForUser( $sUsername ) {
341
+ $sQuery = "
342
+ UPDATE `%s`
343
+ SET `deleted_at` = '%s',
344
+ `expired_at` = '%s'
345
+ WHERE
346
+ `wp_username` = '%s'
347
+ AND `deleted_at` = '0'
348
+ AND `pending` = '0'
349
+ ";
350
+ $sQuery = sprintf( $sQuery,
351
+ $this->getTableName(),
352
+ self::$nRequestTimestamp,
353
+ self::$nRequestTimestamp,
354
+ esc_sql( $sUsername )
355
+ );
356
+ $this->doSql( $sQuery );
357
+ }
358
+
359
+ /**
360
+ *
361
+ */
362
+ protected function query_DoTerminateAllVerifiedLogins() {
363
+ $sQuery = "
364
+ UPDATE `%s`
365
+ SET `deleted_at` = '%s',
366
+ `expired_at` = '%s'
367
+ WHERE
368
+ `deleted_at` = '0'
369
+ AND `pending` = '0'
370
+ ";
371
+ $sQuery = sprintf( $sQuery,
372
+ $this->getTableName(),
373
+ self::$nRequestTimestamp,
374
+ self::$nRequestTimestamp
375
+ );
376
+ return $this->doSql( $sQuery );
377
+ }
378
+
379
+ /**
380
+ * @param $sUniqueId
381
+ */
382
+ public function setAuthActiveCookie( $sUniqueId ) {
383
+ $nWeek = defined( 'WEEK_IN_SECONDS' )? WEEK_IN_SECONDS : 24*60*60;
384
+ setcookie( $this->oFeatureOptions->getTwoFactorAuthCookieName(), $sUniqueId, self::$nRequestTimestamp+$nWeek, COOKIEPATH, COOKIE_DOMAIN, false );
385
+ }
386
+
387
+ /**
388
+ * @param WP_User $oUser
389
+ * @return mixed
390
+ */
391
+ protected function query_GetActiveAuthForUser( $oUser ) {
392
+ $sQuery = "
393
+ SELECT *
394
+ FROM `%s`
395
+ WHERE
396
+ `wp_username` = '%s'
397
+ AND `pending` = '0'
398
+ AND `deleted_at` = '0'
399
+ AND `expired_at` = '0'
400
+ ";
401
+
402
+ $sQuery = sprintf( $sQuery,
403
+ $this->getTableName(),
404
+ $oUser->user_login
405
+ );
406
+ $mResult = $this->selectCustomFromTable( $sQuery );
407
+ return ( is_array( $mResult ) && count( $mResult ) == 1 ) ? $mResult[0] : null ;
408
+ }
409
+
410
+ /**
411
+ * @param $sUniqueId
412
+ * @return bool
413
+ */
414
+ protected function getIsAuthCookieValid( $sUniqueId ) {
415
+ $oDp = $this->loadDataProcessor();
416
+ return $oDp->FetchCookie( $this->oFeatureOptions->getTwoFactorAuthCookieName() ) == $sUniqueId;
417
+ }
418
+
419
+ /**
420
+ * Given the necessary components, creates the 2-factor verification link for giving to the user.
421
+ *
422
+ * @param string $sUser
423
+ * @param string $sUniqueId
424
+ * @return string
425
+ */
426
+ protected function generateTwoFactorVerifyLink( $sUser, $sUniqueId ) {
427
+ $aQueryArgs = array(
428
+ 'wpsfkey' => $this->oFeatureOptions->getTwoAuthSecretKey(),
429
+ 'wpsf-action' => 'linkauth',
430
+ 'username' => $sUser,
431
+ 'uniqueid' => $sUniqueId
432
+ );
433
+ return add_query_arg( $aQueryArgs, home_url() );
434
+ }
435
+
436
+ /**
437
+ * @param WP_User $oUser
438
+ * @param string $sIpAddress
439
+ * @param string $insUniqueId
440
+ * @return boolean
441
+ */
442
+ public function sendEmailTwoFactorVerify( WP_User $oUser, $sIpAddress, $insUniqueId ) {
443
+
444
+ $sEmail = $oUser->user_email;
445
+ $sAuthLink = $this->generateTwoFactorVerifyLink( $oUser->user_login, $insUniqueId );
446
+
447
+ $aMessage = array(
448
+ _wpsf__('You, or someone pretending to be you, just attempted to login into your WordPress site.'),
449
+ _wpsf__('The IP Address / Cookie from which they tried to login is not currently verified.'),
450
+ _wpsf__('Click the following link to validate and complete the login process.') .' '._wpsf__('You will be logged in automatically upon successful authentication.'),
451
+ sprintf( _wpsf__('Username: %s'), $oUser->user_login ),
452
+ sprintf( _wpsf__('IP Address: %s'), $sIpAddress ),
453
+ sprintf( _wpsf__('Authentication Link: %s'), $sAuthLink ),
454
+ );
455
+ $sEmailSubject = sprintf( _wpsf__('Two-Factor Login Verification for: %s'), home_url() );
456
+
457
+ // add filters to email sending (for now only Mandrill)
458
+ add_filter( 'mandrill_payload', array ($this, 'customiseMandrill' ) );
459
+
460
+ $fResult = $this->getEmailProcessor()->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
461
+ if ( $fResult ) {
462
+ $this->logInfo(
463
+ sprintf( _wpsf__('User "%s" was sent an email to verify their Identity using Two-Factor Login Auth for IP address "%s".'), $oUser->user_login, $sIpAddress )
464
+ );
465
+ }
466
+ else {
467
+ $this->logCritical(
468
+ sprintf( _wpsf__('Tried to send User "%s" email to verify their Identity using Two-Factor Login Auth for IP Address "%s", but email sending failed.'), $oUser->user_login, $sIpAddress )
469
+ );
470
+ }
471
+ return $fResult;
472
+ }
473
+
474
+ /**
475
+ * @param array $aMessage
476
+ * @return array
477
+ */
478
+ public function customiseMandrill( $aMessage ) {
479
+ if ( empty( $aMessage['text'] ) ) {
480
+ $aMessage['text'] = $aMessage['html'];
481
+ }
482
+ return $aMessage;
483
+ }
484
+
485
+ /**
486
+ * @return string
487
+ */
488
+ public function getCreateTableSql() {
489
+ $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
490
+ `id` int(11) NOT NULL AUTO_INCREMENT,
491
+ `unique_id` varchar(20) NOT NULL DEFAULT '',
492
+ `wp_username` varchar(255) NOT NULL DEFAULT '',
493
+ `ip` varchar(20) NOT NULL DEFAULT '',
494
+ `ip_long` bigint(20) NOT NULL DEFAULT '0',
495
+ `pending` int(1) NOT NULL DEFAULT '0',
496
+ `created_at` int(15) NOT NULL DEFAULT '0',
497
+ `deleted_at` int(15) NOT NULL DEFAULT '0',
498
+ `expired_at` int(15) NOT NULL DEFAULT '0',
499
+ PRIMARY KEY (`id`)
500
+ ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
501
+ return sprintf( $sSqlTables, $this->getTableName() );
502
+ }
503
+
504
+ /**
505
+ * Assumes that unique_id AND wp_username have been set correctly in the data array (no checking done).
506
+ *
507
+ * @param array $inaData
508
+ * @return array
509
+ */
510
+ protected function getLoginAuthData( $inaData ) {
511
+
512
+ $sQuery = "SELECT * FROM %s WHERE `unique_id` = `%s` AND `wp_username` = %s";
513
+ $sQuery = sprintf( $sQuery, $this->getTableName(), $inaData['unique_id'], $inaData['wp_username'] );
514
+ return $this->selectRowFromTable( $sQuery );
515
+ }
516
+
517
+ /**
518
+ * This is hooked into a cron in the base class and overrides the parent method.
519
+ *
520
+ * It'll delete everything older than 24hrs.
521
+ */
522
+ public function cleanupDatabase() {
523
+ if ( !$this->getTableExists() ) {
524
+ return;
525
+ }
526
+ $nTimeStamp = self::$nRequestTimestamp - (DAY_IN_SECONDS * $this->nDaysToKeepLog);
527
+ $this->deleteAllRowsOlderThan( $nTimeStamp );
528
+ }
529
+
530
+ /**
531
+ * @param $nTimeStamp
532
+ */
533
+ protected function deleteAllRowsOlderThan( $nTimeStamp ) {
534
+ $sQuery = "
535
+ DELETE from `%s`
536
+ WHERE
537
+ `created_at` < '%s'
538
+ AND `pending` = '1'
539
+ ";
540
+ $sQuery = sprintf( $sQuery,
541
+ $this->getTableName(),
542
+ esc_sql( $nTimeStamp )
543
+ );
544
+ $this->doSql( $sQuery );
545
+ }
546
+
547
+ }
548
+ endif;
src/icwp-processor-loginprotect_yubikey.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_LoginProtect_Yubikey') ):
21
+
22
+ class ICWP_WPSF_Processor_LoginProtect_Yubikey extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @const string
26
+ */
27
+ const YubikeyVerifyApiUrl = 'https://api.yubico.com/wsapi/2.0/verify?id=%s&otp=%s&nonce=%s';
28
+
29
+ /**
30
+ * @var ICWP_WPSF_FeatureHandler_LoginProtect
31
+ */
32
+ protected $oFeatureOptions;
33
+
34
+ /**
35
+ */
36
+ public function __construct( ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions ) {
37
+ parent::__construct( $oFeatureOptions );
38
+ }
39
+
40
+ /**
41
+ */
42
+ public function run() {
43
+ if ( $this->getIsYubikeyConfigReady() ) {
44
+ add_filter( 'wp_authenticate_user', array( $this, 'checkYubikeyOtpAuth_Filter' ) );
45
+ add_action( 'login_form', array( $this, 'printYubikeyOtp_Action' ) );
46
+ }
47
+ }
48
+
49
+ /**
50
+ * @param WP_User $oUser
51
+ * @return WP_User|WP_Error
52
+ */
53
+ public function checkYubikeyOtpAuth_Filter( $oUser ) {
54
+ $oError = new WP_Error();
55
+
56
+ // Before anything else we check that a Yubikey pair has been provided for this username (and that there are pairs in the first place!)
57
+ $aYubikeyUsernamePairs = $this->getOption('yubikey_unique_keys');
58
+ if ( !$this->getIsYubikeyConfigReady() ) { // configuration is clearly not completed yet.
59
+ return $oUser;
60
+ }
61
+
62
+ $sOneTimePassword = empty( $_POST['yubiotp'] )? '' : trim( $_POST['yubiotp'] );
63
+ $sAppId = $this->getOption('yubikey_app_id');
64
+ $sApiKey = $this->getOption('yubikey_api_key');
65
+
66
+ // check that if we have a list of permitted keys, that the one used is on that list connected with the username.
67
+ $sYubikey12 = substr( $sOneTimePassword, 0 , 12 );
68
+ $fUsernameFound = false; // if username is never found, it means there's no yubikey specified which means we can bypass this authentication method.
69
+ $fFoundMatch = false;
70
+ foreach( $aYubikeyUsernamePairs as $aUsernameYubikeyPair ) {
71
+ if ( isset( $aUsernameYubikeyPair[$oUser->user_login] ) ) {
72
+ $fUsernameFound = true;
73
+ if ( $aUsernameYubikeyPair[$oUser->user_login] == $sYubikey12 ) {
74
+ $fFoundMatch = true;
75
+ break;
76
+ }
77
+ }
78
+ }
79
+
80
+ // If no yubikey-username pair found for given username, we by-pass Yubikey auth.
81
+ if ( !$fUsernameFound ) {
82
+ $this->logWarning(
83
+ sprintf( _wpsf__('User "%s" logged in without a Yubikey One Time Password because no username-yubikey pair was found for this user.'), $oUser->user_login )
84
+ );
85
+ return $oUser;
86
+ }
87
+
88
+ // Username was found in the list of key pairs, but the yubikey provided didn't match that username.
89
+ if ( !$fFoundMatch ) {
90
+ $oError->add(
91
+ 'yubikey_not_allowed',
92
+ sprintf( _wpsf__( 'ERROR: %s' ), _wpsf__('The Yubikey provided is not on the list of permitted keys for this user.') )
93
+ );
94
+ $this->logWarning(
95
+ sprintf( _wpsf__('User "%s" attempted to login but Yubikey ID used was not in list of authorised keys: "%s".'), $oUser->user_login, $sYubikey12 )
96
+ );
97
+ return $oError;
98
+ }
99
+
100
+ $oFs = $this->loadFileSystemProcessor();
101
+
102
+ $sNonce = md5( uniqid( rand() ) );
103
+ $sUrl = sprintf( self::YubikeyVerifyApiUrl, $sAppId, $sOneTimePassword, $sNonce );
104
+ $sRawYubiRequest = $oFs->getUrlContent( $sUrl );
105
+
106
+ // Validate response.
107
+ // 1. Check OTP and Nonce
108
+ if ( !preg_match( '/otp='.$sOneTimePassword.'/', $sRawYubiRequest, $aMatches )
109
+ || !preg_match( '/nonce='.$sNonce.'/', $sRawYubiRequest, $aMatches )
110
+ ) {
111
+ $oError->add(
112
+ 'yubikey_validate_fail',
113
+ sprintf( _wpsf__( 'ERROR: %s' ), _wpsf__('The Yubikey authentication was not validated successfully.') )
114
+ );
115
+ $this->logWarning(
116
+ sprintf( _wpsf__('User "%s" attempted to login but Yubikey One Time Password failed to validate due to invalid Yubi API.'), $oUser->user_login )
117
+ );
118
+ return $oError;
119
+ }
120
+
121
+ // Optionally we can check the hash, but since we're using HTTPS, this isn't necessary and adds more PHP requirements
122
+
123
+ // 2. Check status directly within response
124
+ preg_match( '/status=([a-zA-Z0-9_]+)/', $sRawYubiRequest, $aMatches );
125
+ $sStatus = $aMatches[1];
126
+
127
+ if ( $sStatus != 'OK' && $sStatus != 'REPLAYED_OTP' ) {
128
+ $oError->add(
129
+ 'yubikey_validate_fail',
130
+ sprintf( _wpsf__( 'ERROR: %s' ), _wpsf__('The Yubikey authentication was not validated successfully.') )
131
+ );
132
+ $this->logWarning(
133
+ sprintf( _wpsf__('User "%s" attempted to login but Yubikey One Time Password failed to validate due to invalid Yubi API response status: %s.'), $oUser->user_login, $sStatus )
134
+ );
135
+ return $oError;
136
+ }
137
+
138
+ $this->logInfo(
139
+ sprintf( _wpsf__('User "%s" successfully logged in using a validated Yubikey One Time Password.'), $oUser->user_login )
140
+ );
141
+ return $oUser;
142
+ }
143
+
144
+ /**
145
+ */
146
+ public function printYubikeyOtp_Action() {
147
+ $sHtml =
148
+ '<p class="yubikey-otp">
149
+ <label>%s<br />
150
+ <input type="text" name="yubiotp" class="input" value="" size="20" />
151
+ </label>
152
+ </p>
153
+ ';
154
+ echo sprintf( $sHtml, '<a href="http://icwp.io/4i" target="_blank">'._wpsf__('Yubikey OTP').'</a>' );
155
+ }
156
+
157
+ /**
158
+ * @return bool
159
+ */
160
+ protected function getIsYubikeyConfigReady() {
161
+ $sAppId = $this->getOption('yubikey_app_id');
162
+ $sApiKey = $this->getOption('yubikey_api_key');
163
+ $aYubikeyKeys = $this->getOption('yubikey_unique_keys');
164
+ return !empty($sAppId) && !empty($sApiKey) && !empty($aYubikeyKeys);
165
+ }
166
+ }
167
+ endif;
src/icwp-processor-plugin.php CHANGED
@@ -15,11 +15,16 @@
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
- require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
- if ( !class_exists('ICWP_WPSF_PluginProcessor') ):
21
 
22
- class ICWP_WPSF_PluginProcessor extends ICWP_WPSF_BaseProcessor {
 
 
 
 
 
23
 
24
  /**
25
  * @param ICWP_WPSF_FeatureHandler_Plugin $oFeatureOptions
@@ -29,18 +34,196 @@ class ICWP_WPSF_PluginProcessor extends ICWP_WPSF_BaseProcessor {
29
  }
30
 
31
  /**
32
- *
33
  */
34
  public function run() {
 
35
  $this->removePluginConflicts();
36
- add_filter( $this->oFeatureOptions->doPluginPrefix( 'show_marketing' ), array( $this, 'getIsShowMarketing' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
 
 
 
 
 
39
  public function getIsShowMarketing( $fShow ) {
40
  if ( !$fShow ) {
41
  return $fShow;
42
  }
43
 
 
 
 
 
44
  $oWpFunctions = $this->loadWpFunctionsProcessor();
45
  if ( class_exists( 'Worpit_Plugin' ) ) {
46
  if ( method_exists( 'Worpit_Plugin', 'IsLinked' ) ) {
@@ -53,10 +236,6 @@ class ICWP_WPSF_PluginProcessor extends ICWP_WPSF_BaseProcessor {
53
  }
54
  }
55
 
56
- if ( $this->getInstallationDays() < 1 ) {
57
- $fShow = false;
58
- }
59
-
60
  return $fShow;
61
  }
62
 
@@ -64,8 +243,8 @@ class ICWP_WPSF_PluginProcessor extends ICWP_WPSF_BaseProcessor {
64
  * @return int
65
  */
66
  protected function getInstallationDays() {
67
- $nTimeInstalled = $this->oFeatureOptions->getOpt( 'installation_time' );
68
- if ( empty($nTimeInstalled) ) {
69
  return 0;
70
  }
71
  return round( ( time() - $nTimeInstalled ) / DAY_IN_SECONDS );
@@ -81,6 +260,21 @@ class ICWP_WPSF_PluginProcessor extends ICWP_WPSF_BaseProcessor {
81
  remove_action( 'init', array( $GLOBALS['aio_wp_security'], 'wp_security_plugin_init'), 0 );
82
  }
83
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  }
85
 
86
  endif;
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
 
20
+ if ( !class_exists('ICWP_WPSF_Processor_Plugin') ):
21
 
22
+ class ICWP_WPSF_Processor_Plugin extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_FeatureHandler_Plugin
26
+ */
27
+ protected $oFeatureOptions;
28
 
29
  /**
30
  * @param ICWP_WPSF_FeatureHandler_Plugin $oFeatureOptions
34
  }
35
 
36
  /**
 
37
  */
38
  public function run() {
39
+ $oFO = $this->getFeatureOptions();
40
  $this->removePluginConflicts();
41
+ add_filter( $oFO->doPluginPrefix( 'show_marketing' ), array( $this, 'getIsShowMarketing' ) );
42
+
43
+ if ( $oFO->getController()->getIsValidAdminArea() ) {
44
+
45
+ // always show this notice
46
+ add_filter( $oFO->doPluginPrefix( 'admin_notices' ), array( $this, 'adminNoticeForceOffActive' ) );
47
+ add_filter( $oFO->doPluginPrefix( 'admin_notices' ), array( $this, 'adminNoticeFeedback' ) );
48
+ if ( $this->getIfShowAdminNotices() ) {
49
+ add_filter( $oFO->doPluginPrefix( 'admin_notices' ), array( $this, 'adminNoticeMailingListSignup' ) );
50
+ add_filter( $oFO->doPluginPrefix( 'admin_notices' ), array( $this, 'adminNoticeTranslations' ) );
51
+ add_filter( $oFO->doPluginPrefix( 'admin_notices' ), array( $this, 'adminNoticePluginUpgradeAvailable' ) );
52
+ add_filter( $oFO->doPluginPrefix( 'admin_notices' ), array( $this, 'adminNoticePostPluginUpgrade' ) );
53
+ }
54
+
55
+ }
56
+ }
57
+
58
+ /**
59
+ * @param array $aAdminNotices
60
+ * @return array
61
+ */
62
+ public function adminNoticeForceOffActive( $aAdminNotices ) {
63
+ $fOverride = $this->getFeatureOptions()->getIfOverride();
64
+ if ( $fOverride ) {
65
+ ob_start();
66
+ include( $this->getFeatureOptions()->getViewSnippet( 'admin_notice_override' ) );
67
+ $sNoticeMessage = ob_get_contents();
68
+ ob_end_clean();
69
+ $aAdminNotices[] = $this->getAdminNoticeHtml( $sNoticeMessage, 'error', false );
70
+ }
71
+ return $aAdminNotices;
72
+ }
73
+
74
+ /**
75
+ * @param array $aAdminNotices
76
+ * @return array
77
+ */
78
+ public function adminNoticeFeedback( $aAdminNotices ) {
79
+ $aAdminFeedbackNotice = $this->getOption( 'feedback_admin_notice' );
80
+
81
+ if ( !empty( $aAdminFeedbackNotice ) && is_array( $aAdminFeedbackNotice ) ) {
82
+
83
+ foreach ( $aAdminFeedbackNotice as $sNotice ) {
84
+ if ( empty( $sNotice ) || !is_string( $sNotice ) ) {
85
+ continue;
86
+ }
87
+ $aAdminNotices[] = $this->getAdminNoticeHtml( '<p>'.$sNotice.'</p>', 'updated', false );
88
+ }
89
+ $this->getFeatureOptions()->doClearAdminFeedback( 'feedback_admin_notice', array() );
90
+ }
91
+
92
+ return $aAdminNotices;
93
+ }
94
+
95
+ /**
96
+ * @param array $aAdminNotices
97
+ * @return array
98
+ */
99
+ public function adminNoticeMailingListSignup( $aAdminNotices ) {
100
+
101
+ $nDays = $this->getInstallationDays();
102
+ if ( $nDays < 2 ) {
103
+ return $aAdminNotices;
104
+ }
105
+
106
+ $sCurrentMetaValue = $this->loadWpFunctionsProcessor()->getUserMeta( $this->getFeatureOptions()->prefixOptionKey( 'plugin_mailing_list_signup' ) );
107
+ if ( $sCurrentMetaValue == 'Y' ) {
108
+ return $aAdminNotices;
109
+ }
110
+
111
+ $sLink_HideNotice = $this->getUrl_PluginDashboard().'&'.$this->getFeatureOptions()->doPluginPrefix( 'hide_mailing_list_signup' ).'=1';
112
+ ob_start();
113
+ include( $this->getFeatureOptions()->getViewSnippet( 'admin_notice_mailchimp' ) );
114
+ $sNoticeMessage = ob_get_contents();
115
+ ob_end_clean();
116
+
117
+ $aAdminNotices[] = $this->getAdminNoticeHtml( $sNoticeMessage, 'updated', false );
118
+ return $aAdminNotices;
119
+ }
120
+
121
+ /**
122
+ * @param array $aAdminNotices
123
+ * @return array
124
+ */
125
+ public function adminNoticePluginUpgradeAvailable( $aAdminNotices ) {
126
+
127
+ $oWp = $this->loadWpFunctionsProcessor();
128
+ // Don't show on the update page
129
+ if ( $oWp->getIsPage_Updates() || !$oWp->getIsPluginUpdateAvailable( $this->getFeatureOptions()->getPluginBaseFile() ) ) {
130
+ return $aAdminNotices;
131
+ }
132
+
133
+ $sNoticeMessage = '<p>'.sprintf( _wpsf__( 'There is an update available for your WordPress Security plugin: %s.' ), '<strong>'.$this->getFeatureOptions()->getController()->getHumanName().'</strong>' ).'</p>';
134
+ $sNoticeMessage .= sprintf( '<a href="%s" class="button">'._wpsf__( 'Please click to update immediately' ).'</a>', $oWp->getPluginUpgradeLink( $this->getFeatureOptions()->getPluginBaseFile() ) );
135
+
136
+ $aAdminNotices[] = $this->getAdminNoticeHtml( $sNoticeMessage, 'updated', false );
137
+ return $aAdminNotices;
138
+ }
139
+
140
+ /**
141
+ * @param array $aAdminNotices
142
+ * @return array
143
+ */
144
+ public function adminNoticePostPluginUpgrade( $aAdminNotices ) {
145
+ $oController = $this->getFeatureOptions()->getController();
146
+ $oWp = $this->loadWpFunctionsProcessor();
147
+
148
+ $sCurrentMetaValue = $oWp->getUserMeta( $oController->doPluginOptionPrefix( 'current_version' ) );
149
+ if ( empty( $sCurrentMetaValue ) || $sCurrentMetaValue === $this->getFeatureOptions()->getVersion() ) {
150
+ return $aAdminNotices;
151
+ }
152
+
153
+ if ( $this->getInstallationDays() <= 1 ) {
154
+ $sMessage = sprintf(
155
+ _wpsf__( "Note: The %s plugin does not automatically turn on feature when you install." ),
156
+ $oController->getHumanName()
157
+ );
158
+ }
159
+ else {
160
+ $sMessage = sprintf(
161
+ _wpsf__( "Note: The %s plugin has been recently upgraded, but please remember that any new features are not automatically enabled." ),
162
+ $oController->getHumanName()
163
+ );
164
+ }
165
+ $sMessage .= '<br />'.sprintf(
166
+ '<a href="%s" id="fromIcwp" title="%s" target="_blank">%s</a>',
167
+ 'http://icwp.io/27',
168
+ $oController->getHumanName(),
169
+ _wpsf__( 'Click to read about any important updates from the plugin home page.' )
170
+ );
171
+ $sButtonText = _wpsf__( 'Okay, hide this notice and go to the plugin dashboard.' );
172
+
173
+ $sMetaFlag = $oController->doPluginPrefix( 'hide_update_notice' );
174
+ $sAction = $oController->getPluginUrl_AdminPage().'&'.$sMetaFlag.'=1';
175
+ $sRedirectPage = $oWp->getUrl_CurrentAdminPage();
176
+ ob_start();
177
+ include( $this->getFeatureOptions()->getViewSnippet( 'admin_notice_plugin_upgraded' ) );
178
+ $sNoticeMessage = ob_get_contents();
179
+ ob_end_clean();
180
+
181
+ $aAdminNotices[] = $this->getAdminNoticeHtml( $sNoticeMessage, 'updated', false );
182
+ return $aAdminNotices;
183
+ }
184
+
185
+ /**
186
+ * @param array $aAdminNotices
187
+ * @return array
188
+ */
189
+ public function adminNoticeTranslations( $aAdminNotices ) {
190
+ if ( $this->getInstallationDays() < 7 ) {
191
+ return $aAdminNotices;
192
+ }
193
+
194
+ $oController = $this->getFeatureOptions()->getController();
195
+
196
+ $oWp = $this->loadWpFunctionsProcessor();
197
+ $sCurrentMetaValue = $oWp->getUserMeta( $oController->doPluginOptionPrefix( 'plugin_translation_notice' ) );
198
+ if ( empty( $sCurrentMetaValue ) || $sCurrentMetaValue === 'Y' ) {
199
+ return $aAdminNotices;
200
+ }
201
+
202
+ ob_start();
203
+ $sMetaFlag = $oController->doPluginPrefix( 'hide_translation_notice' );
204
+ $sAction = $oController->getPluginUrl_AdminPage().'&'.$sMetaFlag.'=1';
205
+ $sRedirectPage = $oWp->getUrl_CurrentAdminPage();
206
+ include( $this->getFeatureOptions()->getViewSnippet( 'admin_notice_translate_plugin' ) );
207
+ $sNoticeMessage = ob_get_contents();
208
+ ob_end_clean();
209
+
210
+ $aAdminNotices[] = $this->getAdminNoticeHtml( $sNoticeMessage, 'updated', false );
211
+ return $aAdminNotices;
212
  }
213
 
214
+ /**
215
+ * @param $fShow
216
+ * @return bool
217
+ */
218
  public function getIsShowMarketing( $fShow ) {
219
  if ( !$fShow ) {
220
  return $fShow;
221
  }
222
 
223
+ if ( $this->getInstallationDays() < 1 ) {
224
+ $fShow = false;
225
+ }
226
+
227
  $oWpFunctions = $this->loadWpFunctionsProcessor();
228
  if ( class_exists( 'Worpit_Plugin' ) ) {
229
  if ( method_exists( 'Worpit_Plugin', 'IsLinked' ) ) {
236
  }
237
  }
238
 
 
 
 
 
239
  return $fShow;
240
  }
241
 
243
  * @return int
244
  */
245
  protected function getInstallationDays() {
246
+ $nTimeInstalled = $this->getFeatureOptions()->getOpt( 'installation_time' );
247
+ if ( empty( $nTimeInstalled ) ) {
248
  return 0;
249
  }
250
  return round( ( time() - $nTimeInstalled ) / DAY_IN_SECONDS );
260
  remove_action( 'init', array( $GLOBALS['aio_wp_security'], 'wp_security_plugin_init'), 0 );
261
  }
262
  }
263
+
264
+ /**
265
+ * @return bool
266
+ */
267
+ protected function getIfShowAdminNotices() {
268
+ return $this->getFeatureOptions()->getOptIs( 'enable_upgrade_admin_notice', 'Y' );
269
+ }
270
+
271
+ /**
272
+ * @param string $sFeaturePage - leave empty to get the main dashboard
273
+ * @return mixed
274
+ */
275
+ protected function getUrl_PluginDashboard( $sFeaturePage = '' ) {
276
+ return network_admin_url( sprintf( 'admin.php?page=%s', $this->getFeatureOptions()->doPluginPrefix( $sFeaturePage ) ) );
277
+ }
278
  }
279
 
280
  endif;
src/icwp-processor-privacyprotect.php CHANGED
@@ -15,11 +15,11 @@
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
- require_once( dirname(__FILE__).'/icwp-basedb-processor.php' );
19
 
20
  if ( !class_exists('ICWP_PrivacyProtectProcessor_V1') ):
21
 
22
- class ICWP_PrivacyProtectProcessor_V1 extends ICWP_BaseDbProcessor_WPSF {
23
 
24
  const TableName = 'privacy_protect';
25
 
@@ -28,19 +28,9 @@ class ICWP_PrivacyProtectProcessor_V1 extends ICWP_BaseDbProcessor_WPSF {
28
  */
29
  public function __construct( ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions ) {
30
  parent::__construct( $oFeatureOptions, self::TableName );
31
- $this->createTable();
32
  $this->reset();
33
  }
34
 
35
- /**
36
- * Resets the object values to be re-used anew
37
- */
38
- public function reset() {
39
- parent::reset();
40
- $this->m_sUniqueToken = '';
41
- $this->m_sCommentStatus = '';
42
- }
43
-
44
  /**
45
  */
46
  public function run() {
@@ -150,7 +140,10 @@ class ICWP_PrivacyProtectProcessor_V1 extends ICWP_BaseDbProcessor_WPSF {
150
  return $aLogData;
151
  }
152
 
153
- public function createTable() {
 
 
 
154
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
155
  `id` int(11) NOT NULL AUTO_INCREMENT,
156
  `request_url` varchar(255) NOT NULL DEFAULT '',
@@ -163,13 +156,12 @@ class ICWP_PrivacyProtectProcessor_V1 extends ICWP_BaseDbProcessor_WPSF {
163
  `deleted_at` int(15) NOT NULL DEFAULT 0,
164
  PRIMARY KEY (`id`)
165
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
166
- $sSqlTables = sprintf( $sSqlTables, $this->getTableName() );
167
- $mResult = $this->doSql( $sSqlTables );
168
  }
169
  }
170
 
171
  endif;
172
 
173
- if ( !class_exists('ICWP_WPSF_PrivacyProtectProcessor') ):
174
- class ICWP_WPSF_PrivacyProtectProcessor extends ICWP_PrivacyProtectProcessor_V1 { }
175
  endif;
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( dirname(__FILE__).'/icwp-processor-basedb.php' );
19
 
20
  if ( !class_exists('ICWP_PrivacyProtectProcessor_V1') ):
21
 
22
+ class ICWP_PrivacyProtectProcessor_V1 extends ICWP_WPSF_BaseDbProcessor {
23
 
24
  const TableName = 'privacy_protect';
25
 
28
  */
29
  public function __construct( ICWP_WPSF_FeatureHandler_LoginProtect $oFeatureOptions ) {
30
  parent::__construct( $oFeatureOptions, self::TableName );
 
31
  $this->reset();
32
  }
33
 
 
 
 
 
 
 
 
 
 
34
  /**
35
  */
36
  public function run() {
140
  return $aLogData;
141
  }
142
 
143
+ /**
144
+ * @return string
145
+ */
146
+ public function getCreateTableSql() {
147
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
148
  `id` int(11) NOT NULL AUTO_INCREMENT,
149
  `request_url` varchar(255) NOT NULL DEFAULT '',
156
  `deleted_at` int(15) NOT NULL DEFAULT 0,
157
  PRIMARY KEY (`id`)
158
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
159
+ return sprintf( $sSqlTables, $this->getTableName() );
 
160
  }
161
  }
162
 
163
  endif;
164
 
165
+ if ( !class_exists('ICWP_WPSF_Processor_PrivacyProtect') ):
166
+ class ICWP_WPSF_Processor_PrivacyProtect extends ICWP_PrivacyProtectProcessor_V1 { }
167
  endif;
src/{icwp-processor-usermanagement.php → icwp-processor-user_management.php} RENAMED
@@ -15,11 +15,11 @@
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
- require_once( dirname(__FILE__).'/icwp-basedb-processor.php' );
19
 
20
  if ( !class_exists('ICWP_WPSF_Processor_UserManagement_V1') ):
21
 
22
- class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
23
 
24
  const Session_Cookie = 'wpsf_sesh_id';
25
 
@@ -41,17 +41,28 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
41
  * @param ICWP_WPSF_FeatureHandler_UserManagement $oFeatureOptions
42
  */
43
  public function __construct( ICWP_WPSF_FeatureHandler_UserManagement $oFeatureOptions ) {
44
- parent::__construct( $oFeatureOptions );
45
- $this->createTable();
46
  }
47
 
48
  /**
49
  */
50
  public function run() {
51
  parent::run();
52
- $this->loadDataProcessor();
53
 
54
- $sRequestMethod = ICWP_WPSF_DataProcessor::ArrayFetch( $_SERVER, 'REQUEST_METHOD' );
 
 
 
 
 
 
 
 
 
 
 
 
55
  $fIsPost = strtolower( empty($sRequestMethod)? '' : $sRequestMethod ) == 'post';
56
 
57
  // Check the current logged-in user every page load.
@@ -68,13 +79,16 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
68
  add_filter( 'authenticate', array( $this, 'createNewUserSession_Filter' ), 30, 3);
69
 
70
  // When we know user has successfully authenticated and we activate the session entry in the database
71
- add_action( 'wp_login', array( $this, 'activateUserSession' ) );
 
 
72
 
73
  add_action( 'wp_logout', array( $this, 'onWpLogout' ) );
74
 
75
  add_filter( 'wp_login_errors', array( $this, 'addLoginMessage' ) );
76
  }
77
 
 
78
  /**
79
  * @param WP_Error $oError
80
  * @return WP_Error
@@ -85,8 +99,8 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
85
  $oError = new WP_Error();
86
  }
87
 
88
- $this->loadDataProcessor();
89
- $sForceLogout = ICWP_WPSF_DataProcessor::FetchGet( 'wpsf-forcelogout' );
90
  if ( $sForceLogout == 1 ) {
91
  $oError->add( 'wpsf-forcelogout', _wpsf__('Your session has expired.').'<br />'._wpsf__('Please login again.') );
92
  }
@@ -96,6 +110,12 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
96
  else if ( $sForceLogout == 3 ) {
97
  $oError->add( 'wpsf-forcelogout', _wpsf__('Your session was locked to another IP Address.').'<br />'._wpsf__('Please login again.') );
98
  }
 
 
 
 
 
 
99
  return $oError;
100
  }
101
 
@@ -105,10 +125,28 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
105
  public function checkCurrentUser_Action() {
106
  $this->getSessionId();
107
  if ( is_user_logged_in() ) {
108
- $oUser = wp_get_current_user();
109
- $this->doVerifyCurrentUser( $oUser );
110
- $this->updateSessionLastActivityAt( $oUser );
111
- $this->updateSessionLastActivityUri( $oUser );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  }
113
  }
114
 
@@ -120,44 +158,39 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
120
  return false;
121
  }
122
 
 
 
123
  $aLoginSessionData = $this->getUserSessionRecord( $oUser->user_login );
124
  if ( !$aLoginSessionData ) {
125
- $this->doLogout();
126
  }
127
 
128
  // check timeout interval
129
  $nSessionTimeoutInterval = $this->getSessionTimeoutInterval();
130
  if ( $nSessionTimeoutInterval > 0 && ( self::$nRequestTimestamp - $aLoginSessionData['logged_in_at'] > $nSessionTimeoutInterval ) ) {
131
- $this->doLogout( 'wpsf-forcelogout=1' );
132
  }
133
 
134
  // check idle timeout interval
135
  $nSessionIdleTimeoutInterval = $this->getOption( 'session_idle_timeout_interval', 0 ) * HOUR_IN_SECONDS;
136
  if ( intval($nSessionIdleTimeoutInterval) > 0 && ( (self::$nRequestTimestamp - $aLoginSessionData['last_activity_at']) > $nSessionIdleTimeoutInterval ) ) {
137
- $this->doLogout( 'wpsf-forcelogout=2' );
138
  }
139
 
140
  // check login ip address
141
  $fLockToIp = $this->getIsOption( 'session_lock_location', 'Y' );
142
  if ( $fLockToIp && self::$nRequestIp != $aLoginSessionData['ip_long'] ) {
143
- $this->doLogout( 'wpsf-forcelogout=3' );
144
  }
 
 
145
  }
146
 
147
  /**
148
  * @return integer
149
  */
150
  protected function getSessionTimeoutInterval( ) {
151
- return $this->getOption( 'session_timeout_interval', 0 ) * DAY_IN_SECONDS;
152
- }
153
-
154
- /**
155
- *
156
- */
157
- protected function doLogout( $sParams = '' ) {
158
- $oWp = $this->loadWpFunctionsProcessor();
159
- $oWp->logoutUser();
160
- $oWp->redirectToLogin( $sParams );
161
  }
162
 
163
  /**
@@ -173,7 +206,7 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
173
  * Should return false when logging is disabled.
174
  *
175
  * @return false|array - false when logging is disabled, array with log data otherwise
176
- * @see ICWP_WPSF_BaseProcessor::getLogData()
177
  */
178
  public function flushLogData() {
179
 
@@ -220,33 +253,41 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
220
  *
221
  */
222
  public function onWpLogout() {
223
- $oUser = wp_get_current_user();
224
- $this->doTerminateUserSession( $oUser->user_login );
225
  }
226
 
227
  /**
228
- * @param $sUsername
229
  * @return boolean
230
  */
231
- protected function doTerminateUserSession( $sUsername ) {
232
- if ( empty( $sUsername ) ) {
 
 
233
  return false;
234
  }
235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  $aNewData = array(
237
  'deleted_at' => self::$nRequestTimestamp
238
  );
239
  $aWhere = array(
240
- 'session_id' => $this->getSessionId(),
241
  'wp_username' => $sUsername,
242
  'deleted_at' => 0
243
  );
244
- $mResult = $this->updateRowsFromTable( $aNewData, $aWhere );
245
-
246
- unset( $_COOKIE[ self::Session_Cookie ] );
247
- setcookie( self::Session_Cookie, "", time()-3600, COOKIEPATH, COOKIE_DOMAIN, false );
248
-
249
- return $mResult;
250
  }
251
 
252
  /**
@@ -258,7 +299,7 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
258
  return false;
259
  }
260
 
261
- $this->loadDataProcessor();
262
  // Add new session entry
263
  // set attempts = 1 and then when we know it's a valid login, we zero it.
264
  // First set any other entries for the given user to be deleted.
@@ -270,7 +311,7 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
270
  $aNewData[ 'pending' ] = 1;
271
  $aNewData[ 'logged_in_at' ] = self::$nRequestTimestamp;
272
  $aNewData[ 'last_activity_at' ] = self::$nRequestTimestamp;
273
- $aNewData[ 'last_activity_uri' ] = ICWP_WPSF_DataProcessor::FetchServer( 'REQUEST_URI' );
274
  $aNewData[ 'created_at' ] = self::$nRequestTimestamp;
275
  $mResult = $this->insertIntoTable( $aNewData );
276
 
@@ -280,7 +321,17 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
280
  /**
281
  */
282
  protected function setSessionCookie() {
283
- setcookie( self::Session_Cookie, $this->getSessionId(), time()+$this->getSessionTimeoutInterval(), COOKIEPATH, COOKIE_DOMAIN, false );
 
 
 
 
 
 
 
 
 
 
284
  }
285
 
286
  /**
@@ -297,19 +348,26 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
297
  'login_attempts' => $aSessionData['login_attempts'] + 1
298
  );
299
  return $this->updateCurrentSession( $sUsername, $aNewData );
300
- return $mResult;
301
  }
302
 
303
  /**
304
  * @param string $sUsername
305
  * @return boolean
306
  */
307
- public function activateUserSession( $sUsername ) {
308
  if ( empty( $sUsername ) ) {
309
  return false;
310
  }
 
 
 
 
 
 
 
 
 
311
 
312
- // First set any other entries for the given user to be deleted.
313
  $aNewData = array(
314
  'pending' => 0,
315
  'logged_in_at' => self::$nRequestTimestamp,
@@ -328,6 +386,48 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
328
  return $mResult;
329
  }
330
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  /**
332
  * @param WP_User $oUser
333
  * @return boolean
@@ -337,7 +437,6 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
337
  return false;
338
  }
339
 
340
- // First set any other entries for the given user to be deleted.
341
  $aNewData = array(
342
  'last_activity_at' => self::$nRequestTimestamp
343
  );
@@ -353,10 +452,9 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
353
  return false;
354
  }
355
 
356
- $this->loadDataProcessor();
357
- // First set any other entries for the given user to be deleted.
358
  $aNewData = array(
359
- 'last_activity_uri' => ICWP_WPSF_DataProcessor::FetchServer( 'REQUEST_URI' )
360
  );
361
  $mResult = $this->updateCurrentSession( $oUser->user_login, $aNewData );
362
  return $mResult;
@@ -368,8 +466,18 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
368
  * @return boolean
369
  */
370
  protected function updateCurrentSession( $sUsername, $aUpdateData ) {
 
 
 
 
 
 
 
 
 
 
371
  $aWhere = array(
372
- 'session_id' => $this->getSessionId(),
373
  'deleted_at' => 0,
374
  'wp_username' => $sUsername
375
  );
@@ -399,6 +507,31 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
399
  return $this->selectCustomFromTable( $sQuery );
400
  }
401
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  /**
403
  * Checks for and gets a user session.
404
  *
@@ -426,6 +559,33 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
426
  return $this->selectCustomFromTable( $sQuery );
427
  }
428
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
  /**
430
  * Checks for and gets a user session.
431
  *
@@ -452,12 +612,7 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
452
  if ( is_array( $mResult ) && count( $mResult ) == 1 ) {
453
  return $mResult[0];
454
  }
455
- else {
456
- $this->logWarning(
457
- sprintf( _wpsf__('User "%s" was found to be un-verified at the given IP Address "%s"'), $sUsername, long2ip( self::$nRequestIp ) )
458
- );
459
- return false;
460
- }
461
  }
462
 
463
  /**
@@ -465,9 +620,9 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
465
  */
466
  protected function getSessionId() {
467
  if ( empty( $this->sSessionId ) ) {
468
- $this->loadDataProcessor();
469
- $this->sSessionId = ICWP_WPSF_DataProcessor::FetchCookie( self::Session_Cookie );
470
- if ( is_null( $this->sSessionId ) ) {
471
  $this->sSessionId = md5( uniqid() );
472
  $this->setSessionCookie();
473
  }
@@ -475,9 +630,10 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
475
  return $this->sSessionId;
476
  }
477
 
478
- public function createTable() {
479
-
480
- // Set up login processor table
 
481
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
482
  `id` int(11) NOT NULL AUTO_INCREMENT,
483
  `session_id` varchar(32) NOT NULL DEFAULT '',
@@ -493,8 +649,7 @@ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_BaseDbProcessor_WPSF {
493
  `deleted_at` int(15) NOT NULL DEFAULT '0',
494
  PRIMARY KEY (`id`)
495
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
496
- $sSqlTables = sprintf( $sSqlTables, $this->getTableName() );
497
- $mResult = $this->doSql( $sSqlTables );
498
  }
499
 
500
  /**
@@ -532,4 +687,4 @@ endif;
532
 
533
  if ( !class_exists('ICWP_WPSF_Processor_UserManagement') ):
534
  class ICWP_WPSF_Processor_UserManagement extends ICWP_WPSF_Processor_UserManagement_V1 { }
535
- endif;
15
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
  */
17
 
18
+ require_once( dirname(__FILE__).'/icwp-processor-basedb.php' );
19
 
20
  if ( !class_exists('ICWP_WPSF_Processor_UserManagement_V1') ):
21
 
22
+ class ICWP_WPSF_Processor_UserManagement_V1 extends ICWP_WPSF_BaseDbProcessor {
23
 
24
  const Session_Cookie = 'wpsf_sesh_id';
25
 
41
  * @param ICWP_WPSF_FeatureHandler_UserManagement $oFeatureOptions
42
  */
43
  public function __construct( ICWP_WPSF_FeatureHandler_UserManagement $oFeatureOptions ) {
44
+ parent::__construct( $oFeatureOptions, $oFeatureOptions->getUserSessionsTableName() );
 
45
  }
46
 
47
  /**
48
  */
49
  public function run() {
50
  parent::run();
51
+ $oDp = $this->loadDataProcessor();
52
 
53
+ $oWp = $this->oFeatureOptions->loadWpFunctionsProcessor();
54
+ // XML-RPC Compatibility
55
+ if ( $oWp->getIsXmlrpc() && $this->getIsOption( 'enable_xmlrpc_compatibility', 'Y' ) ) {
56
+ return true;
57
+ }
58
+
59
+ if ( is_email( $this->getOption( 'enable_admin_login_email_notification' ) ) ) {
60
+ require_once('icwp-processor-usermanagement_adminloginnotification.php');
61
+ $oNotificationProcessor = new ICWP_WPSF_Processor_UserManagement_AdminLoginNotification( $this->oFeatureOptions );
62
+ $oNotificationProcessor->run();
63
+ }
64
+
65
+ $sRequestMethod = $oDp->FetchServer( 'REQUEST_METHOD' );
66
  $fIsPost = strtolower( empty($sRequestMethod)? '' : $sRequestMethod ) == 'post';
67
 
68
  // Check the current logged-in user every page load.
79
  add_filter( 'authenticate', array( $this, 'createNewUserSession_Filter' ), 30, 3);
80
 
81
  // When we know user has successfully authenticated and we activate the session entry in the database
82
+ add_action( 'wp_login', array( $this, 'handleUserSession' ) );
83
+
84
+ // add_action( 'wp_loaded', array( $this, 'autoForwardFromLogin' ) );
85
 
86
  add_action( 'wp_logout', array( $this, 'onWpLogout' ) );
87
 
88
  add_filter( 'wp_login_errors', array( $this, 'addLoginMessage' ) );
89
  }
90
 
91
+
92
  /**
93
  * @param WP_Error $oError
94
  * @return WP_Error
99
  $oError = new WP_Error();
100
  }
101
 
102
+ $oDp = $this->loadDataProcessor();
103
+ $sForceLogout = $oDp->FetchGet( 'wpsf-forcelogout' );
104
  if ( $sForceLogout == 1 ) {
105
  $oError->add( 'wpsf-forcelogout', _wpsf__('Your session has expired.').'<br />'._wpsf__('Please login again.') );
106
  }
110
  else if ( $sForceLogout == 3 ) {
111
  $oError->add( 'wpsf-forcelogout', _wpsf__('Your session was locked to another IP Address.').'<br />'._wpsf__('Please login again.') );
112
  }
113
+ else if ( $sForceLogout == 4 ) {
114
+ $oError->add( 'wpsf-forcelogout', _wpsf__('You do not currently have a Simple Firewall user session.').'<br />'._wpsf__('Please login again.') );
115
+ }
116
+ else if ( $sForceLogout == 5 ) {
117
+ $oError->add( 'wpsf-forcelogout', _wpsf__('An administrator has terminated this session.').'<br />'._wpsf__('Please login again.') );
118
+ }
119
  return $oError;
120
  }
121
 
125
  public function checkCurrentUser_Action() {
126
  $this->getSessionId();
127
  if ( is_user_logged_in() ) {
128
+ $oWp = $this->loadWpFunctionsProcessor();
129
+ $oUser = $oWp->getCurrentWpUser();
130
+
131
+ // only check the non-admin areas if specified to do so and it's not AJAX (we've removed the option to check admin only)
132
+ // if ( !$oWp->getIsAjax() && ( is_admin() || !$this->getIsOption( 'session_check_admin_area_only', 'Y' ) ) ) {
133
+ if ( is_admin() ) {
134
+ $this->doVerifyCurrentUser( $oUser );
135
+ }
136
+
137
+ // At this point session is validated
138
+
139
+ // This used to be an option, but to simplify, we've removed it and do it anyway.
140
+ if ( true || $this->getIsOption( 'session_auto_forward_to_admin_area', 'Y' ) ) {
141
+ $oDp = $this->loadDataProcessor();
142
+ $sWpLogin = 'wp-login.php';
143
+ if ( $oDp->FetchGet( 'action' ) != 'logout' && ( substr( $oWp->getCurrentPage(), -strlen( $sWpLogin ) ) === $sWpLogin ) ) {
144
+ $oWp->redirectToAdmin();
145
+ }
146
+ }
147
+
148
+ // always track activity
149
+ $this->updateSessionLastActivity( $oUser );
150
  }
151
  }
152
 
158
  return false;
159
  }
160
 
161
+ $oWp = $this->loadWpFunctionsProcessor();
162
+
163
  $aLoginSessionData = $this->getUserSessionRecord( $oUser->user_login );
164
  if ( !$aLoginSessionData ) {
165
+ $oWp->forceUserRelogin( array( 'wpsf-forcelogout' => 4 ) );
166
  }
167
 
168
  // check timeout interval
169
  $nSessionTimeoutInterval = $this->getSessionTimeoutInterval();
170
  if ( $nSessionTimeoutInterval > 0 && ( self::$nRequestTimestamp - $aLoginSessionData['logged_in_at'] > $nSessionTimeoutInterval ) ) {
171
+ $oWp->forceUserRelogin( array( 'wpsf-forcelogout' => 1 ) );
172
  }
173
 
174
  // check idle timeout interval
175
  $nSessionIdleTimeoutInterval = $this->getOption( 'session_idle_timeout_interval', 0 ) * HOUR_IN_SECONDS;
176
  if ( intval($nSessionIdleTimeoutInterval) > 0 && ( (self::$nRequestTimestamp - $aLoginSessionData['last_activity_at']) > $nSessionIdleTimeoutInterval ) ) {
177
+ $oWp->forceUserRelogin( array( 'wpsf-forcelogout' => 2 ) );
178
  }
179
 
180
  // check login ip address
181
  $fLockToIp = $this->getIsOption( 'session_lock_location', 'Y' );
182
  if ( $fLockToIp && self::$nRequestIp != $aLoginSessionData['ip_long'] ) {
183
+ $oWp->forceUserRelogin( array( 'wpsf-forcelogout' => 3 ) );
184
  }
185
+
186
+ return true;
187
  }
188
 
189
  /**
190
  * @return integer
191
  */
192
  protected function getSessionTimeoutInterval( ) {
193
+ return $this->getOption( 'session_timeout_interval' ) * DAY_IN_SECONDS;
 
 
 
 
 
 
 
 
 
194
  }
195
 
196
  /**
206
  * Should return false when logging is disabled.
207
  *
208
  * @return false|array - false when logging is disabled, array with log data otherwise
209
+ * @see ICWP_WPSF_Processor_Base::getLogData()
210
  */
211
  public function flushLogData() {
212
 
253
  *
254
  */
255
  public function onWpLogout() {
256
+ $this->doTerminateCurrentUserSession();
 
257
  }
258
 
259
  /**
 
260
  * @return boolean
261
  */
262
+ protected function doTerminateCurrentUserSession() {
263
+ $oWp = $this->loadWpFunctionsProcessor();
264
+ $oUser = $oWp->getCurrentWpUser();
265
+ if ( empty( $oUser->user_login ) ) {
266
  return false;
267
  }
268
 
269
+ $mResult = $this->doTerminateUserSession( $oUser->user_login, $this->getSessionId() );
270
+ unset( $_COOKIE[ $this->oFeatureOptions->getUserSessionCookieName() ] );
271
+ setcookie( $this->oFeatureOptions->getUserSessionCookieName(), "", time()-3600, COOKIEPATH, COOKIE_DOMAIN, false );
272
+ return $mResult;
273
+ }
274
+
275
+ /**
276
+ * @param string $sUsername
277
+ * @param string $sSessionId
278
+ * @return boolean
279
+ */
280
+ protected function doTerminateUserSession( $sUsername, $sSessionId ) {
281
+
282
  $aNewData = array(
283
  'deleted_at' => self::$nRequestTimestamp
284
  );
285
  $aWhere = array(
286
+ 'session_id' => $sSessionId,
287
  'wp_username' => $sUsername,
288
  'deleted_at' => 0
289
  );
290
+ return $this->updateRowsFromTable( $aNewData, $aWhere );
 
 
 
 
 
291
  }
292
 
293
  /**
299
  return false;
300
  }
301
 
302
+ $oDp = $this->loadDataProcessor();
303
  // Add new session entry
304
  // set attempts = 1 and then when we know it's a valid login, we zero it.
305
  // First set any other entries for the given user to be deleted.
311
  $aNewData[ 'pending' ] = 1;
312
  $aNewData[ 'logged_in_at' ] = self::$nRequestTimestamp;
313
  $aNewData[ 'last_activity_at' ] = self::$nRequestTimestamp;
314
+ $aNewData[ 'last_activity_uri' ] = $oDp->FetchServer( 'REQUEST_URI' );
315
  $aNewData[ 'created_at' ] = self::$nRequestTimestamp;
316
  $mResult = $this->insertIntoTable( $aNewData );
317
 
321
  /**
322
  */
323
  protected function setSessionCookie() {
324
+ if ( $this->getSessionTimeoutInterval() > 0 ) {
325
+ $oWp = $this->loadWpFunctionsProcessor();
326
+ setcookie(
327
+ $this->oFeatureOptions->getUserSessionCookieName(),
328
+ $this->getSessionId(),
329
+ self::$nRequestTimestamp + $this->getSessionTimeoutInterval(),
330
+ $oWp->getCookiePath(),
331
+ $oWp->getCookieDomain(),
332
+ false
333
+ );
334
+ }
335
  }
336
 
337
  /**
348
  'login_attempts' => $aSessionData['login_attempts'] + 1
349
  );
350
  return $this->updateCurrentSession( $sUsername, $aNewData );
 
351
  }
352
 
353
  /**
354
  * @param string $sUsername
355
  * @return boolean
356
  */
357
+ public function handleUserSession( $sUsername ) {
358
  if ( empty( $sUsername ) ) {
359
  return false;
360
  }
361
+ $this->activateUserSession( $sUsername );
362
+ $this->doLimitUserSession( $sUsername );
363
+ }
364
+
365
+ /**
366
+ * @param string $sUsername
367
+ * @return boolean
368
+ */
369
+ protected function activateUserSession( $sUsername ) {
370
 
 
371
  $aNewData = array(
372
  'pending' => 0,
373
  'logged_in_at' => self::$nRequestTimestamp,
386
  return $mResult;
387
  }
388
 
389
+ /**
390
+ * @param string $sUsername
391
+ * @return boolean
392
+ */
393
+ protected function doLimitUserSession( $sUsername ) {
394
+
395
+ $nSessionLimit = $this->getOption( 'session_username_concurrent_limit', 1 );
396
+ if ( $nSessionLimit <= 0 ) {
397
+ return true;
398
+ }
399
+
400
+ $aSessions = $this->getActiveSessionRecordsForUser( $sUsername );
401
+ $nSessionsToKill = count( $aSessions ) - $nSessionLimit;
402
+ if ( $nSessionsToKill < 1 ) {
403
+ return true;
404
+ }
405
+
406
+ for( $nCount = 0; $nCount < $nSessionsToKill; $nCount++ ) {
407
+ $mResult = $this->doTerminateUserSession( $aSessions[$nCount]['wp_username'], $aSessions[$nCount]['session_id'] );
408
+ }
409
+ return $mResult;
410
+ }
411
+
412
+ /**
413
+ * This is the same as both updateSessionLastActivityAt() and updateSessionLastActivityUri()
414
+ *
415
+ * @param WP_User $oUser
416
+ * @return boolean
417
+ */
418
+ protected function updateSessionLastActivity( $oUser ) {
419
+ if ( !is_object( $oUser ) || ! ( $oUser instanceof WP_User ) ) {
420
+ return false;
421
+ }
422
+
423
+ $oDp = $this->loadDataProcessor();
424
+ $aNewData = array(
425
+ 'last_activity_at' => self::$nRequestTimestamp,
426
+ 'last_activity_uri' => $oDp->FetchServer( 'REQUEST_URI' )
427
+ );
428
+ return $this->updateCurrentSession( $oUser->user_login, $aNewData );
429
+ }
430
+
431
  /**
432
  * @param WP_User $oUser
433
  * @return boolean
437
  return false;
438
  }
439
 
 
440
  $aNewData = array(
441
  'last_activity_at' => self::$nRequestTimestamp
442
  );
452
  return false;
453
  }
454
 
455
+ $oDp = $this->loadDataProcessor();
 
456
  $aNewData = array(
457
+ 'last_activity_uri' => $oDp->FetchServer( 'REQUEST_URI' )
458
  );
459
  $mResult = $this->updateCurrentSession( $oUser->user_login, $aNewData );
460
  return $mResult;
466
  * @return boolean
467
  */
468
  protected function updateCurrentSession( $sUsername, $aUpdateData ) {
469
+ return $this->updateSession( $this->getSessionId(), $sUsername, $aUpdateData );
470
+ }
471
+
472
+ /**
473
+ * @param string $sSessionId
474
+ * @param string $sUsername
475
+ * @param array $aUpdateData
476
+ * @return boolean
477
+ */
478
+ protected function updateSession( $sSessionId, $sUsername, $aUpdateData ) {
479
  $aWhere = array(
480
+ 'session_id' => $sSessionId,
481
  'deleted_at' => 0,
482
  'wp_username' => $sUsername
483
  );
507
  return $this->selectCustomFromTable( $sQuery );
508
  }
509
 
510
+ /**
511
+ * Checks for and gets a user session.
512
+ *
513
+ * @param string $sUsername
514
+ * @return array|boolean
515
+ */
516
+ public function getActiveSessionRecordsForUser( $sUsername ) {
517
+
518
+ $sQuery = "
519
+ SELECT *
520
+ FROM `%s`
521
+ WHERE
522
+ `wp_username` = '%s'
523
+ AND `pending` = '0'
524
+ AND `deleted_at` = '0'
525
+ ORDER BY `last_activity_at` ASC
526
+ ";
527
+ $sQuery = sprintf(
528
+ $sQuery,
529
+ $this->getTableName(),
530
+ $sUsername
531
+ );
532
+ return $this->selectCustomFromTable( $sQuery );
533
+ }
534
+
535
  /**
536
  * Checks for and gets a user session.
537
  *
559
  return $this->selectCustomFromTable( $sQuery );
560
  }
561
 
562
+ /**
563
+ * Checks for and gets a user session.
564
+ *
565
+ * @param string $sSessionId
566
+ * @return array|boolean
567
+ */
568
+ protected function getSessionRecord( $sSessionId = null ) {
569
+
570
+ $sQuery = "
571
+ SELECT *
572
+ FROM `%s`
573
+ WHERE
574
+ `session_id` = '%s'
575
+ AND `deleted_at` = '0'
576
+ ";
577
+ $sQuery = sprintf( $sQuery,
578
+ $this->getTableName(),
579
+ empty( $sSessionId ) ? $this->getSessionId() : $sSessionId
580
+ );
581
+
582
+ $mResult = $this->selectCustomFromTable( $sQuery );
583
+ if ( is_array( $mResult ) && count( $mResult ) == 1 ) {
584
+ return $mResult[0];
585
+ }
586
+ return false;
587
+ }
588
+
589
  /**
590
  * Checks for and gets a user session.
591
  *
612
  if ( is_array( $mResult ) && count( $mResult ) == 1 ) {
613
  return $mResult[0];
614
  }
615
+ return false;
 
 
 
 
 
616
  }
617
 
618
  /**
620
  */
621
  protected function getSessionId() {
622
  if ( empty( $this->sSessionId ) ) {
623
+ $oDp = $this->loadDataProcessor();
624
+ $this->sSessionId = $oDp->FetchCookie( $this->oFeatureOptions->getUserSessionCookieName() );
625
+ if ( empty( $this->sSessionId ) ) {
626
  $this->sSessionId = md5( uniqid() );
627
  $this->setSessionCookie();
628
  }
630
  return $this->sSessionId;
631
  }
632
 
633
+ /**
634
+ * @return string
635
+ */
636
+ public function getCreateTableSql() {
637
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
638
  `id` int(11) NOT NULL AUTO_INCREMENT,
639
  `session_id` varchar(32) NOT NULL DEFAULT '',
649
  `deleted_at` int(15) NOT NULL DEFAULT '0',
650
  PRIMARY KEY (`id`)
651
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
652
+ return sprintf( $sSqlTables, $this->getTableName() );
 
653
  }
654
 
655
  /**
687
 
688
  if ( !class_exists('ICWP_WPSF_Processor_UserManagement') ):
689
  class ICWP_WPSF_Processor_UserManagement extends ICWP_WPSF_Processor_UserManagement_V1 { }
690
+ endif;
src/icwp-processor-usermanagement_adminloginnotification.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
8
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
10
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
12
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
13
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
+ */
17
+
18
+ require_once( dirname(__FILE__).'/icwp-processor-base.php' );
19
+
20
+ if ( !class_exists('ICWP_WPSF_Processor_UserManagement_AdminLoginNotification') ):
21
+
22
+ class ICWP_WPSF_Processor_UserManagement_AdminLoginNotification extends ICWP_WPSF_Processor_Base {
23
+
24
+ /**
25
+ * @param ICWP_WPSF_FeatureHandler_UserManagement $oFeatureOptions
26
+ */
27
+ public function __construct( ICWP_WPSF_FeatureHandler_UserManagement $oFeatureOptions ) {
28
+ parent::__construct( $oFeatureOptions );
29
+ }
30
+
31
+ public function run() {
32
+ if ( is_email( $this->getOption( 'enable_admin_login_email_notification' ) ) ) {
33
+ add_action( 'wp_login', array( $this, 'sendLoginEmailNotification' ) );
34
+ }
35
+ }
36
+
37
+ /**
38
+ * @param $sUsername
39
+ * @return mixed
40
+ */
41
+ public function sendLoginEmailNotification( $sUsername ) {
42
+
43
+ if ( empty( $sUsername ) ) {
44
+ return false;
45
+ }
46
+
47
+ $oUser = get_user_by( 'login', $sUsername );
48
+ if ( !( $oUser instanceof WP_User ) ) {
49
+ return false;
50
+ }
51
+
52
+ $fIsAdministrator = isset( $oUser->caps['administrator'] ) && $oUser->caps['administrator'];
53
+
54
+ if ( !$fIsAdministrator ) {
55
+ return false;
56
+ }
57
+
58
+ $oDp = $this->loadDataProcessor();
59
+ $oEmailer = $this->getFeatureOptions()->getEmailProcessor();
60
+
61
+ $aMessage = array(
62
+ _wpsf__( 'As requested, the WordPress Simple Firewall is notifying you of an administrator login to a WordPress site that you manage.' ),
63
+ _wpsf__( 'Details for this user are below:' ),
64
+ '- '.sprintf( _wpsf__( 'Site URL: %s' ), home_url() ),
65
+ '- '.sprintf( _wpsf__( 'Username: %s' ), $sUsername ),
66
+ '- '.sprintf( _wpsf__( 'IP Address: %s' ), $oDp->GetVisitorIpAddress( false ) ),
67
+ _wpsf__( 'Thanks.' )
68
+ );
69
+
70
+ $fResult = $oEmailer->sendEmailTo(
71
+ $this->getOption( 'enable_admin_login_email_notification' ),
72
+ sprintf( 'Email Notice: An Administrator Just Logged Into %s', home_url() ),
73
+ $aMessage
74
+ );
75
+ return $fResult;
76
+ }
77
+ }
78
+
79
+ endif;
src/icwp-processor-yaml.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
5
+ * All rights reserved.
6
+ *
7
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
8
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
10
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
11
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
12
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
13
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
14
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
15
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
16
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17
+ *
18
+ */
19
+
20
+ if ( !class_exists('ICWP_WPSF_YamlProcessor_V1') ):
21
+
22
+ class ICWP_WPSF_YamlProcessor_V1 {
23
+
24
+ /**
25
+ * @param string $sYamlString
26
+ * @return array
27
+ */
28
+ public function parseYamlString( $sYamlString ) {
29
+ if ( ! $this->loadYamlParser() ) {
30
+ return null;
31
+ }
32
+ return Spyc::YAMLLoadString( $sYamlString );
33
+ }
34
+
35
+ /**
36
+ */
37
+ protected function loadYamlParser() {
38
+ if ( !class_exists( 'Spyc' ) ) {
39
+ require_once( 'lib/yaml/Spyc.php' );
40
+ }
41
+ return class_exists( 'Spyc' );
42
+ }
43
+ }
44
+ endif;
45
+
46
+ if ( !class_exists('ICWP_WPSF_YamlProcessor') ):
47
+
48
+ class ICWP_WPSF_YamlProcessor extends ICWP_WPSF_YamlProcessor_V1 {
49
+
50
+ /**
51
+ * @var ICWP_WPSF_YamlProcessor
52
+ */
53
+ protected static $oInstance = NULL;
54
+
55
+ /**
56
+ * @return ICWP_WPSF_YamlProcessor
57
+ */
58
+ public static function GetInstance() {
59
+ if ( is_null( self::$oInstance ) ) {
60
+ self::$oInstance = new self();
61
+ }
62
+ return self::$oInstance;
63
+ }
64
+ }
65
+ endif;
src/icwp-pure-base.php CHANGED
@@ -1,949 +1,376 @@
1
  <?php
2
 
3
- if ( !defined('ICWP_DS') ) {
4
- define( 'ICWP_DS', DIRECTORY_SEPARATOR );
5
- }
6
-
7
- require_once( dirname(__FILE__).'/icwp-once.php' );
8
- require_once( dirname(__FILE__).'/icwp-wpfunctions.php' );
9
- require_once( dirname(__FILE__).'/icwp-wpfilesystem.php' );
10
-
11
- if ( !class_exists('ICWP_Pure_Base_V5') ):
12
-
13
- class ICWP_Pure_Base_V5 extends ICWP_WPSF_Once {
14
-
15
- const ViewExt = '.php';
16
- const ViewDir = 'views';
17
-
18
- /**
19
- * @var ICWP_Wordpress_Simple_Firewall_Plugin
20
- */
21
- protected $oPluginVo;
22
-
23
- /**
24
- * Set to true if it should never be shown in the dashboard
25
- * @var string
26
- */
27
- protected $fHeadless = false;
28
-
29
- /**
30
- * Set to true if this contains components from another plugin to stand alone
31
- * @var string
32
- */
33
- protected $m_sAutoUpdateUrl = '';
34
-
35
- /**
36
- * @var string
37
- */
38
- protected $sPluginRootFile;
39
- /**
40
- * @var string
41
- */
42
- protected $sPluginFileName;
43
- /**
44
- * @var string
45
- */
46
- protected $sPluginRootDir;
47
- /**
48
- * @var string
49
- */
50
- protected $sPluginBaseFile;
51
- /**
52
- * @var string
53
- */
54
- protected $sPluginUrl;
55
- /**
56
- * @var string
57
- */
58
- protected static $sOptionPrefix = '';
59
-
60
- protected $aPluginMenu;
61
-
62
- protected $sPluginSlug;
63
-
64
- protected $fShowMarketing;
65
-
66
- /**
67
- * @var ICWP_WpFunctions_WPSF;
68
- */
69
- protected $m_oWpFunctions;
70
-
71
- /**
72
- * @var ICWP_WpFilesystem_WPSF;
73
- */
74
- protected $m_oWpFs;
75
-
76
- public function __construct( ICWP_Wordpress_Simple_Firewall_Plugin $oPluginVo ) {
77
-
78
- // All core values of the plugin are derived from the values stored in this value object.
79
- $this->oPluginVo = $oPluginVo;
80
- $this->sPluginRootFile = $this->oPluginVo->getRootFile();
81
- $this->sPluginSlug = $this->oPluginVo->getPluginSlug();
82
- self::$sOptionPrefix = $this->oPluginVo->getOptionStoragePrefix();
83
- $this->setPaths();
84
-
85
- add_action( 'plugins_loaded', array( $this, 'onWpPluginsLoaded' ) );
86
- add_action( 'init', array( $this, 'onWpInit' ), 0 );
87
- if ( $this->isValidAdminArea() ) {
88
- add_action( 'admin_init', array( $this, 'onWpAdminInit' ) );
89
- add_action( 'admin_notices', array( $this, 'onWpAdminNotices' ) );
90
- add_action( 'network_admin_notices', array( $this, 'onWpAdminNotices' ) );
91
- add_action( 'admin_menu', array( $this, 'onWpAdminMenu' ) );
92
- add_action( 'network_admin_menu', array( $this, 'onWpAdminMenu' ) );
93
- add_action( 'plugin_action_links', array( $this, 'onWpPluginActionLinks' ), 10, 4 );
94
- // add_action( 'deactivate_plugin', array( $this, 'onWpHookDeactivatePlugin' ), 1, 1 );
95
- add_action( 'wp_before_admin_bar_render', array( $this, 'onWpAdminBar' ), 1, 9999 );
96
- }
97
- add_action( 'in_plugin_update_message-'.$this->getPluginBaseFile(), array( $this, 'onWpPluginUpdateMessage' ) );
98
- add_action( 'shutdown', array( $this, 'onWpShutdown' ) );
99
- add_action( $this->doPluginPrefix( 'plugin_shutdown' ), array( $this, 'doPluginShutdown' ) );
100
 
101
- $this->registerActivationHooks();
102
- }
103
 
104
- /**
105
- * Returns this unique plugin prefix
106
- *
107
- * @param string $sGlue
108
- * @return string
109
- */
110
- public function getPluginPrefix( $sGlue = '-' ) {
111
- return $this->oPluginVo->getFullPluginPrefix( $sGlue );
112
- }
113
 
114
- /**
115
- * Will prefix and return any string with the unique plugin prefix.
116
- *
117
- * @param string $sSuffix
118
- * @param string $sGlue
119
- * @return string
120
- */
121
- public function doPluginPrefix( $sSuffix = '', $sGlue = '-' ) {
122
- $sPrefix = $this->oPluginVo->getFullPluginPrefix( $sGlue );
123
-
124
- if ( $sSuffix == $sPrefix || strpos( $sSuffix, $sPrefix.$sGlue ) === 0 ) { //it already has the prefix
125
- return $sSuffix;
126
- }
127
 
128
- return sprintf( '%s%s%s', $sPrefix, empty($sSuffix)? '' : $sGlue, empty($sSuffix)? '' : $sSuffix );
129
- }
130
-
131
- protected function isValidAdminArea() {
132
- $this->loadWpFunctions();
133
- if ( !$this->m_oWpFunctions->isMultisite() && is_admin() ) {
134
- return true;
135
- }
136
- else if ( $this->m_oWpFunctions->isMultisite() && $this->oPluginVo->getIsWpmsNetworkAdminOnly() && is_network_admin() ) {
137
- return true;
138
- }
139
- return false;
140
- }
141
-
142
- /**
143
- * Registers the plugins activation, deactivate and uninstall hooks.
144
- */
145
- protected function registerActivationHooks() {
146
- register_activation_hook( $this->sPluginRootFile, array( $this, 'onWpActivatePlugin' ) );
147
- register_deactivation_hook( $this->sPluginRootFile, array( $this, 'onWpDeactivatePlugin' ) );
148
- // register_uninstall_hook( $this->sPluginRootFile, array( $this, 'onWpUninstallPlugin' ) );
149
- }
150
-
151
- /**
152
- * @since v3.0.0
153
- */
154
- protected function setPaths() {
155
- if ( empty( $this->sPluginRootFile ) ) {
156
- $this->sPluginRootFile = __FILE__;
157
- }
158
- $this->sPluginFileName = basename( $this->sPluginRootFile );
159
- $this->getPluginBaseFile();
160
- $this->sPluginRootDir = dirname( $this->sPluginRootFile ).ICWP_DS;
161
- $this->sPluginUrl = plugins_url( '/', $this->sPluginRootFile ) ; //this seems to use SSL more reliably than WP_PLUGIN_URL
162
- }
163
-
164
- /**
165
- * This is the path to the main plugin file relative to the WordPress plugins directory.
166
- *
167
- * @return string
168
- */
169
- public function getPluginBaseFile() {
170
- if ( !isset( $this->sPluginBaseFile ) ) {
171
- $this->sPluginBaseFile = plugin_basename( $this->sPluginRootFile );
172
- }
173
- return $this->sPluginBaseFile;
174
- }
175
 
176
- /**
177
- * @param boolean $fHasPermission
178
- * @return boolean
179
- */
180
- public function hasPermissionToView( $fHasPermission = true ) {
181
- return $this->hasPermissionToSubmit( $fHasPermission );
182
- }
183
 
184
- /**
185
- * @param boolean $fHasPermission
186
- * @return boolean
187
- */
188
- public function hasPermissionToSubmit( $fHasPermission = true ) {
189
- // first a basic admin check
190
- return $fHasPermission && is_super_admin() && current_user_can( $this->oPluginVo->getBasePermissions() );
191
- }
192
-
193
- public function doPluginUpdateCheck() {
194
- $oWp = $this->loadWpFunctions();
195
- $oWp->getIsPluginUpdateAvailable( $this->getPluginBaseFile() );
196
- }
197
-
198
- protected function display( $insView, $inaData = array() ) {
199
- $sFile = $this->sPluginRootDir.self::ViewDir.ICWP_DS.$insView.self::ViewExt;
200
-
201
- if ( !is_file( $sFile ) ) {
202
- echo "View not found: ".$sFile;
203
- return false;
204
- }
205
-
206
- if ( count( $inaData ) > 0 ) {
207
- extract( $inaData, EXTR_PREFIX_ALL, $this->oPluginVo->getParentSlug() ); //slug being 'icwp'
208
- }
209
 
210
- ob_start();
211
- include( $sFile );
212
- $sContents = ob_get_contents();
213
- ob_end_clean();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
- echo $sContents;
216
- return true;
217
- }
218
 
219
- protected function getSubmenuId( $sId = '' ) {
220
- return $this->doPluginPrefix( $sId );
221
- }
 
222
 
223
- /**
224
- * Hooked to 'plugins_loaded'
225
- */
226
- public function onWpPluginsLoaded() {
227
- if ( is_admin() ) {
228
- //Handle plugin upgrades
229
- $this->doPluginUpdateCheck();
230
- $this->load_textdomain();
231
  }
232
- $this->handlePluginFormSubmit();
233
- add_filter( 'all_plugins', array( $this, 'filter_hidePluginFromTableList' ) );
234
- add_filter( 'site_transient_update_plugins', array( $this, 'filter_hidePluginUpdatesFromUI' ) );
235
- }
236
 
237
- /**
238
- * Added to a WordPress filter ('all_plugins') which will remove this particular plugin from the
239
- * list of all plugins based on the "plugin file" name.
240
- *
241
- * @uses $this->m_fHeadless if the plugin is headless, it is hidden
242
- * @param array $aPlugins
243
- * @return array
244
- */
245
- public function filter_hidePluginFromTableList( $aPlugins ) {
246
-
247
- if ( !$this->fHeadless ) {
248
- return $aPlugins;
249
  }
250
 
251
- $sPluginBaseFileName = $this->getPluginBaseFile();
252
- if ( isset( $aPlugins[$sPluginBaseFileName] ) ) {
253
- unset( $aPlugins[$sPluginBaseFileName] );
254
- }
255
- return $aPlugins;
256
- }
257
-
258
- /**
259
- * Added to the WordPress filter ('site_transient_update_plugins') in order to remove visibility of updates
260
- * from the WordPress Admin UI.
261
- *
262
- * In order to ensure that WordPress still checks for plugin updates it will not remove this plugin from
263
- * the list of plugins if DOING_CRON is set to true.
264
- *
265
- * @uses $this->fHeadless if the plugin is headless, it is hidden
266
- * @param StdClass $oPlugins
267
- * @return StdClass
268
- */
269
- public function filter_hidePluginUpdatesFromUI( $oPlugins ) {
270
-
271
- if ( ( defined( 'DOING_CRON' ) && DOING_CRON ) || !$this->fHeadless ) {
272
- return $oPlugins;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  }
274
 
275
- if ( !empty( $oPlugins->response[ $this->getPluginBaseFile() ] ) ) {
276
- unset( $oPlugins->response[ $this->getPluginBaseFile() ] );
 
 
 
 
277
  }
278
 
279
- return $oPlugins;
280
- }
281
-
282
- /**
283
- * Load the multilingual aspect of the plugin
284
- */
285
- public function load_textdomain() {
286
- //TODO: Can replace with $this->sPluginRootDir ?
287
- load_plugin_textdomain( $this->oPluginVo->getTextDomain(), false, dirname( $this->getPluginBaseFile() ) . '/languages/' );
288
- }
289
-
290
- public function onWpInit() { }
291
-
292
- public function onWpAdminInit() {
293
- //Do Plugin-Specific Admin Work
294
- if ( $this->getIsPage_PluginAdmin() ) {
295
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueueBootstrapLegacyAdminCss' ), 99 );
296
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueuePluginAdminCss' ), 99 );
297
- }
298
- }
299
-
300
- public function onWpAdminMenu() {
301
- if ( !$this->isValidAdminArea() ) {
302
- return true;
303
- }
304
- $this->createMenu();
305
- }
306
-
307
- protected function createMenu() {
308
-
309
- if ( $this->fHeadless ) {
310
- return true;
311
- }
312
-
313
- $sFullParentMenuId = $this->getPluginPrefix();
314
- add_menu_page( $this->oPluginVo->getHumanName(), $this->oPluginVo->getAdminMenuTitle(), $this->oPluginVo->getBasePermissions(), $sFullParentMenuId, array( $this, 'onDisplayAll' ), $this->getPluginLogoUrl16() );
315
- //Create and Add the submenu items
316
- // $this->createPluginSubMenuItems();
317
-
318
- // allow for any plugin menu items that don't come from filters
319
- add_filter( $this->doPluginPrefix( 'filter_plugin_submenu_items' ), array( $this, 'filter_addExtraAdminMenuItems' ) );
320
-
321
- $aPluginMenuItems = apply_filters( $this->doPluginPrefix( 'filter_plugin_submenu_items' ), array() );
322
- if ( !empty( $aPluginMenuItems ) ) {
323
- foreach ( $aPluginMenuItems as $sMenuTitle => $aMenu ) {
324
- list( $sMenuItemText, $sMenuItemId, $aMenuCallBack ) = $aMenu;
325
- add_submenu_page(
326
- $sFullParentMenuId,
327
- $sMenuTitle,
328
- $sMenuItemText,
329
- $this->oPluginVo->getBasePermissions(),
330
- $this->doPluginPrefix( $sMenuItemId ),
331
- $aMenuCallBack
332
- );
333
  }
334
  }
335
- // if ( !empty($this->aPluginMenu) ) {
336
- // foreach ( $this->aPluginMenu as $sMenuTitle => $aMenu ) {
337
- // list( $sMenuItemText, $sMenuItemId, $sMenuCallBack ) = $aMenu;
338
- // add_submenu_page( $sFullParentMenuId, $sMenuTitle, $sMenuItemText, $this->oPluginVo->getBasePermissions(), $sMenuItemId, array( $this, $sMenuCallBack ) );
339
- // }
340
- // }
341
- $this->fixSubmenu();
342
- }
343
 
344
- /**
345
- * @param array $aItems
346
- * @return array
347
- */
348
- public function filter_addExtraAdminMenuItems( $aItems ) {
349
- return $aItems;
350
- }
351
 
352
- /**
353
- * no longer used
354
- */
355
- protected function createPluginSubMenuItems() { }
356
-
357
- protected function fixSubmenu() {
358
- global $submenu;
359
- $sFullParentMenuId = $this->getPluginPrefix();
360
- if ( isset( $submenu[$sFullParentMenuId] ) ) {
361
- unset( $submenu[$sFullParentMenuId][0] );
362
- // $submenu[$sFullParentMenuId][0][0] = 'Dashboard';
363
  }
364
- }
365
-
366
- /**
367
- * Displaying all views now goes through this central function and we work out
368
- * what to display based on the name of current hook/filter being processed.
369
- */
370
- public function onDisplayAll() {
371
- $this->onDisplayMainMenu();
372
- }
373
-
374
- /**
375
- * The callback function for the main admin menu index page
376
- */
377
- public function onDisplayMainMenu() {
378
- $aData = array();
379
- $this->display( $this->doPluginPrefix( 'index', '_' ), $aData );
380
- }
381
 
382
- protected function getBaseDisplayData( $sSubmenu = '' ) {
383
- return array(
384
- 'plugin_url' => $this->sPluginUrl,
385
- 'var_prefix' => self::$sOptionPrefix,
386
- 'sPluginName' => $this->oPluginVo->getHumanName(),
387
- 'fShowAds' => $this->isShowMarketing(),
388
- 'nonce_field' => $this->getPluginPrefix(),
389
- 'form_action' => 'admin.php?page='.$this->getCurrentWpAdminPage()
390
- );
391
- }
392
-
393
- /**
394
- */
395
- protected function getCurrentWpAdminPage() {
396
- $sScript = isset( $_SERVER['SCRIPT_NAME'] )? $_SERVER['SCRIPT_NAME'] : $_SERVER['PHP_SELF'];
397
- if ( is_admin() && !empty( $sScript ) && basename( $sScript ) == 'admin.php' ) {
398
- $sCurrentPage = $this->fetchGet('page');
399
  }
400
- return empty($sCurrentPage)? '' : $sCurrentPage;
401
- }
402
 
403
- /**
404
- */
405
- protected function getIsPage_PluginMainDashboard() {
406
- return ( $this->getCurrentWpAdminPage() == $this->getPluginPrefix() );
407
- }
408
-
409
- /**
410
- */
411
- protected function getIsPage_PluginAdmin() {
412
- return ( strpos( $this->getCurrentWpAdminPage(), $this->getPluginPrefix() ) === 0 );
413
- }
414
-
415
- /**
416
- * @param string $sFeaturePage - leave empty to get the main dashboard
417
- * @return mixed
418
- */
419
- protected function getUrl_PluginDashboard( $sFeaturePage = '' ) {
420
- return network_admin_url( sprintf( 'admin.php?page=%s', $this->getSubmenuId( $sFeaturePage ) ) );
421
- }
422
 
423
- /**
424
- * @return bool
425
- */
426
- protected function isShowMarketing() {
427
 
428
- if ( isset($this->fShowMarketing) ) {
429
- return $this->fShowMarketing;
430
- }
431
- $this->fShowMarketing = true;
432
- if ( class_exists( 'Worpit_Plugin' ) ) {
433
- if ( method_exists( 'Worpit_Plugin', 'IsLinked' ) ) {
434
- $this->fShowMarketing = !Worpit_Plugin::IsLinked();
435
  }
436
- else if ( function_exists( 'get_option' )
 
 
 
 
 
437
  && get_option( Worpit_Plugin::$VariablePrefix.'assigned' ) == 'Y'
438
  && get_option( Worpit_Plugin::$VariablePrefix.'assigned_to' ) != '' ) {
439
-
440
- $this->fShowMarketing = false;
441
- }
442
- }
443
- return $this->fShowMarketing ;
444
- }
445
-
446
- /**
447
- * On the plugins listing page, hides the edit and deactivate links
448
- * for this plugin based on permissions
449
- *
450
- * @see ICWP_Pure_Base_V1::onWpPluginActionLinks()
451
- */
452
- public function onWpPluginActionLinks( $aActionLinks, $sPluginFile ) {
453
-
454
- if ( $sPluginFile == $this->getPluginBaseFile() ) {
455
- if ( !$this->hasPermissionToSubmit() ) {
456
- if ( array_key_exists( 'edit', $aActionLinks ) ) {
457
- unset( $aActionLinks['edit'] );
458
- }
459
- if ( array_key_exists( 'deactivate', $aActionLinks ) ) {
460
- unset( $aActionLinks['deactivate'] );
461
  }
462
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
 
464
- $sSettingsLink = sprintf( '<a href="%s">%s</a>', $this->getUrl_PluginDashboard(), _wpsf__( 'Dashboard' ) ); ;
465
- array_unshift( $aActionLinks, $sSettingsLink );
 
 
466
  }
467
- return $aActionLinks;
468
- }
469
 
470
- /**
471
- * Override this method to handle all the admin notices
472
- */
473
- public function onWpAdminNotices() {
474
- // Do we have admin priviledges?
475
- if ( !$this->isValidAdminArea() || !current_user_can( $this->oPluginVo->getBasePermissions() ) ) {
476
  return true;
477
  }
478
 
479
- $this->doAdminNoticeOptionsUpdated();
480
-
481
- // If we've set to not show admin notices ever
482
- if ( $this->getShowAdminNotices() ) {
483
-
484
- if ( $this->hasPermissionToView() ) {
485
- $this->doAdminNoticePostUpgrade();
486
- $this->doAdminNoticeTranslations();
487
- $this->doAdminNoticeMailingListSignup();
488
- }
489
- if ( $this->hasPermissionToSubmit() ) {
490
- $this->doAdminNoticePluginUpgradeAvailable();
491
- }
492
  }
493
- }
494
-
495
- protected function doAdminNoticePluginUpgradeAvailable() {
496
 
497
- // Don't show on the update page.
498
- if ( isset( $GLOBALS['pagenow'] ) && $GLOBALS['pagenow'] == 'update.php' ) {
499
- return;
 
 
 
 
 
 
500
  }
501
 
502
- $this->loadWpFunctions();
503
- $oUpdate = $this->m_oWpFunctions->getIsPluginUpdateAvailable( $this->getPluginBaseFile() );
504
- if ( !$oUpdate ) {
505
- return;
506
- }
507
- $sNotice = $this->getAdminNoticeHtml_PluginUpgradeAvailable();
508
- $this->getAdminNoticeHtml( $sNotice, 'updated', true );
509
- }
510
-
511
- protected function doAdminNoticeOptionsUpdated(){
512
- $sHtml = $this->getAdminNoticeHtml_OptionsUpdated();
513
- if ( !empty($sHtml) ) {
514
- $this->getAdminNoticeHtml( $sHtml, 'updated', true );
515
  }
516
- }
517
-
518
- protected function doAdminNoticePostUpgrade() {
519
 
520
- $sCurrentMetaValue = $this->getUserMeta( 'current_version' );
521
- if ( $sCurrentMetaValue === $this->oPluginVo->getVersion() ) {
522
- return;
523
- }
524
- $sHtml = $this->getAdminNoticeHtml_VersionUpgrade();
525
- if ( !empty($sHtml) ) {
526
- $this->getAdminNoticeHtml( $sHtml, 'updated', true );
527
  }
528
- }
529
 
530
- /**
531
- *
532
- */
533
- protected function doAdminNoticeTranslations(){
534
 
535
- $sCurrentMetaValue = $this->getUserMeta( 'plugin_translation_notice' );
536
- if ( $sCurrentMetaValue === 'Y' ) {
537
- return;
538
- }
539
-
540
- $sHtml = $this->getAdminNoticeHtml_Translations();
541
- if ( !empty($sHtml) ) {
542
- $this->getAdminNoticeHtml( $sHtml, 'updated', true );
543
  }
544
- }
545
 
546
- /**
547
- *
548
- */
549
- protected function doAdminNoticeMailingListSignup(){
550
-
551
- $sCurrentMetaValue = $this->getUserMeta( 'plugin_mailing_list_signup' );
552
- if ( $sCurrentMetaValue == 'Y' ) {
553
- return;
554
  }
555
 
556
- $sHtml = $this->getAdminNoticeHtml_MailingListSignup();
557
- if ( !empty($sHtml) ) {
558
- $this->getAdminNoticeHtml( $sHtml, 'updated', true );
 
559
  }
560
- }
561
 
562
- /**
563
- * Override this to change the message for the particular plugin upgrade.
564
- */
565
- protected function getAdminNoticeHtml_PluginUpgradeAvailable() {
566
- $sUpgradeLink = $this->m_oWpFunctions->getPluginUpgradeLink( $this->getPluginBaseFile() );
567
- $sNotice = '<p>There is an update available for the %s plugin. <a href="%s">Click to update immediately</a>.</p>';
568
- $sNotice = sprintf( $sNotice, $this->oPluginVo->getHumanName(), $sUpgradeLink );
569
- return $sNotice;
570
- }
571
 
572
- protected function getAdminNoticeHtml_OptionsUpdated() { }
573
- protected function getAdminNoticeHtml_VersionUpgrade() { }
574
- protected function getAdminNoticeHtml_Translations() { }
575
- protected function getAdminNoticeHtml_MailingListSignup() { }
576
-
577
- /**
578
- * Provides the basic HTML template for printing a WordPress Admin Notices
579
- *
580
- * @param $insNotice - The message to be displayed.
581
- * @param $insMessageClass - either error or updated
582
- * @param $infPrint - if true, will echo. false will return the string
583
- * @return boolean|string
584
- */
585
- protected function getAdminNoticeHtml( $insNotice = '', $insMessageClass = 'updated', $infPrint = false ) {
586
-
587
- $sFullNotice = '
588
- <div id="message" class="'.$insMessageClass.'">
589
- <style>#message form { margin: 0px; padding-bottom: 8px; }</style>
590
- '.$insNotice.'
591
- </div>
592
- ';
593
-
594
- if ( $infPrint ) {
595
- echo $sFullNotice;
596
- return true;
597
- } else {
598
- return $sFullNotice;
599
  }
600
- }
601
-
602
- /**
603
- *
604
- */
605
- protected function getShowAdminNotices() {
606
- return true;
607
- }
608
 
609
- /**
610
- * Updates the current (or supplied user ID) user meta data with the version of the plugin
611
- *
612
- * @param $nId
613
- * @param $sValue
614
- */
615
- protected function updateTranslationNoticeShownUserMeta( $nId = '', $sValue = 'Y' ) {
616
- $this->updateUserMeta( 'plugin_translation_notice', $sValue, $nId );
617
- }
618
-
619
- /**
620
- * Updates the current (or supplied user ID) user meta data with the version of the plugin
621
- *
622
- * @param $nId
623
- * @param $sValue
624
- */
625
- protected function updateMailingListSignupShownUserMeta( $nId = '', $sValue = 'Y' ) {
626
- $this->updateUserMeta( 'plugin_mailing_list_signup', $sValue, $nId );
627
- }
628
-
629
- /**
630
- * Updates the current (or supplied user ID) user meta data with the version of the plugin
631
- *
632
- * @param integer $nId
633
- */
634
- protected function updateVersionUserMeta( $nId = null ) {
635
- $this->updateUserMeta( 'current_version', $this->oPluginVo->getVersion(), $nId );
636
- }
637
-
638
- /**
639
- * Updates the current (or supplied user ID) user meta data with the version of the plugin
640
- *
641
- * @param string $insKey
642
- * @param mixed $mValue
643
- * @param integer $innId -user ID
644
- * @return boolean
645
- */
646
- protected function updateUserMeta( $insKey, $mValue, $innId = null ) {
647
- if ( empty( $innId ) ) {
648
- $oCurrentUser = $this->getCurrentUser();
649
- if ( !$oCurrentUser ) {
650
  return;
651
  }
652
- $nUserId = $oCurrentUser->ID;
653
- }
654
- else {
655
- $nUserId = $innId;
656
- }
657
- return update_user_meta( $nUserId, self::$sOptionPrefix.$insKey, $mValue );
658
- }
659
-
660
- protected function getUserMeta( $sKey ) {
661
-
662
- $oCurrentUser = $this->getCurrentUser();
663
- if ( !$oCurrentUser ) {
664
- return;
665
- }
666
- $nUserId = $oCurrentUser->ID;
667
-
668
- $sCurrentMetaValue = get_user_meta( $nUserId, $this->doPluginPrefix( $sKey, '_' ), true );
669
- // A guard whereby if we can't ever get a value for this meta, it means we can never set it.
670
- if ( empty( $sCurrentMetaValue ) ) {
671
- //the value has never been set, or it's been installed for the first time.
672
- $this->updateUserMeta( $sKey, 'temp', $nUserId );
673
- return ''; //meaning we don't show the update notice upon new installations and for those people who can't set the version in their meta.
674
- }
675
- return $sCurrentMetaValue;
676
- }
677
-
678
- /**
679
- * @return mixed
680
- */
681
- protected function getCurrentUser() {
682
- if( !is_user_logged_in() ) {
683
- return false;
684
- }
685
- global $current_user;
686
- get_currentuserinfo();
687
- return $current_user;
688
- }
689
-
690
- protected function handlePluginFormSubmit() {
691
- if ( !$this->isIcwpPluginFormSubmit() ) {
692
- return false;
693
- }
694
- // check_admin_referer( $this->getPluginPrefix() );
695
-
696
- // do all the plugin feature/options saving
697
- do_action( $this->doPluginPrefix( 'form_submit' ) );
698
-
699
- if ( $this->getIsPage_PluginAdmin() ) {
700
- wp_safe_redirect( $this->getUrl_PluginDashboard( $this->getCurrentWpAdminPage() ) );
701
- return true;
702
- }
703
- }
704
-
705
- /**
706
- * @return bool
707
- */
708
- protected function isIcwpPluginFormSubmit() {
709
- if ( empty($_POST) && empty($_GET) ) {
710
- return false;
711
- }
712
-
713
- $aFormSubmitOptions = array(
714
- 'icwp_plugin_form_submit',
715
- 'icwp_link_action',
716
- 'icwp_wpsf_admin_access_key_request'
717
- );
718
- foreach( $aFormSubmitOptions as $sOption ) {
719
- if ( !is_null( $this->fetchRequest( $sOption, false ) ) ) {
720
- return true;
721
  }
722
  }
723
- return false;
724
- }
725
-
726
- public function enqueueBootstrapAdminCss() {
727
- $sUnique = $this->doPluginPrefix( 'bootstrap_wpadmin_css' );
728
- wp_register_style( $sUnique, $this->getCssUrl( 'bootstrap-wpadmin.css' ), false, $this->oPluginVo->getVersion() );
729
- wp_enqueue_style( $sUnique );
730
- }
731
-
732
- public function enqueueBootstrapLegacyAdminCss() {
733
- $sUnique = $this->doPluginPrefix( 'bootstrap_wpadmin_legacy_css' );
734
- wp_register_style( $sUnique, $this->getCssUrl( 'bootstrap-wpadmin-legacy.css' ), false, $this->oPluginVo->getVersion() );
735
- wp_enqueue_style( $sUnique );
736
-
737
- $sUnique = $this->doPluginPrefix( 'bootstrap_wpadmin_css_fixes' );
738
- wp_register_style( $sUnique, $this->getCssUrl('bootstrap-wpadmin-fixes.css'), array( $this->doPluginPrefix( 'bootstrap_wpadmin_legacy_css' ) ), $this->oPluginVo->getVersion() );
739
- wp_enqueue_style( $sUnique );
740
- }
741
-
742
- public function enqueuePluginAdminCss() {
743
- $sUnique = $this->doPluginPrefix( 'plugin_css', '_' );
744
- wp_register_style( $sUnique, $this->getCssUrl('plugin.css'), array( $this->doPluginPrefix( 'bootstrap_wpadmin_css_fixes' ) ), $this->oPluginVo->getVersion() );
745
- wp_enqueue_style( $sUnique );
746
- }
747
- protected function redirect( $insUrl, $innTimeout = 1 ) {
748
- echo '
749
- <script type="text/javascript">
750
- function redirect() {
751
- window.location = "'.$insUrl.'";
752
- }
753
- var oTimer = setTimeout( "redirect()", "'.($innTimeout * 1000).'" );
754
- </script>';
755
- }
756
-
757
- /**
758
- * Displays a message in the plugins listing when a plugin has an update available.
759
- */
760
- public function onWpPluginUpdateMessage() {
761
- echo '<div style="color: #dd3333;">'
762
- .$this->getPluginsListUpdateMessage()
763
- . '</div>';
764
- }
765
-
766
- protected function getPluginsListUpdateMessage() {
767
- return '';
768
- }
769
-
770
- /**
771
- * Hooked to 'deactivate_plugin' and can be used to interrupt the deactivation of this plugin.
772
- * @param string $insPlugin
773
- */
774
- public function onWpHookDeactivatePlugin( $insPlugin ) {
775
- if ( strpos( $insPlugin, $this->sPluginFileName ) !== false ) {
776
- $this->doPreventDeactivation( $insPlugin );
777
- }
778
- }
779
-
780
- /**
781
- * @param string $insPlugin - the path to the plugin file
782
- */
783
- protected function doPreventDeactivation( $insPlugin ) {
784
- if ( !$this->hasPermissionToSubmit() ) {
785
- wp_die( 'Sorry, you do not have permission to disable this plugin. You need to authenticate first.' );
786
- }
787
- }
788
 
789
- /**
790
- * Use this to wrap up the function when the PHP process is coming to an end. Call from onWpShudown()
791
- */
792
- public function doPluginShutdown() { }
793
-
794
- /**
795
- * Hooked to 'shutdown'
796
- */
797
- public function onWpShutdown() {
798
- do_action( $this->doPluginPrefix( 'plugin_shutdown' ) );
799
- }
800
-
801
- public function onWpActivatePlugin() { }
802
- public function onWpDeactivatePlugin() { }
803
- public function onWpUninstallPlugin() { }
804
-
805
- /**
806
- * @return ICWP_WpFunctions_WPSF
807
- */
808
- protected function loadWpFunctions() {
809
- if ( !isset( $this->m_oWpFunctions ) ) {
810
- $this->m_oWpFunctions = ICWP_WpFunctions_WPSF::GetInstance();
811
- }
812
- return $this->m_oWpFunctions;
813
- }
814
 
815
- /**
816
- * @return ICWP_WpFilesystem_WPSF
817
- */
818
- protected function loadWpFilesystem() {
819
- return ICWP_WpFilesystem_WPSF::GetInstance();;
820
- }
821
-
822
- protected function flushCaches() {
823
- if (function_exists('w3tc_pgcache_flush')) {
824
- w3tc_pgcache_flush();
825
- }
826
- }
827
 
828
- protected function getImageUrl( $insImage ) {
829
- return $this->sPluginUrl.'resources/images/'.$insImage;
830
- }
831
- protected function getCssUrl( $insCss ) {
832
- return $this->sPluginUrl.'resources/css/'.$insCss;
833
- }
834
- protected function getJsUrl( $insJs ) {
835
- return $this->sPluginUrl.'resources/js/'.$insJs;
836
- }
837
-
838
- /**
839
- * @param string $insKey
840
- * @param boolean $infIncludeCookie
841
- * @return mixed|null
842
- */
843
- protected function fetchRequest( $insKey, $infIncludeCookie = true ) {
844
- $mFetchVal = $this->fetchPost( $insKey );
845
- if ( is_null( $mFetchVal ) ) {
846
- $mFetchVal = $this->fetchGet( $insKey );
847
- if ( is_null( $mFetchVal && $infIncludeCookie ) ) {
848
- $mFetchVal = $this->fetchCookie( $insKey );
849
  }
850
- }
851
- return $mFetchVal;
852
- }
853
- /**
854
- * @param string $insKey
855
- * @return mixed|null
856
- */
857
- protected function fetchGet( $insKey ) {
858
- if ( function_exists( 'filter_input' ) && defined( 'INPUT_GET' ) ) {
859
- return filter_input( INPUT_GET, $insKey );
860
- }
861
- return $this->arrayFetch( $_GET, $insKey );
862
- }
863
- /**
864
- * @param string $insKey The $_POST key
865
- * @return mixed|null
866
- */
867
- protected function fetchPost( $insKey ) {
868
- if ( function_exists( 'filter_input' ) && defined( 'INPUT_POST' ) ) {
869
- return filter_input( INPUT_POST, $insKey );
870
- }
871
- return $this->arrayFetch( $_POST, $insKey );
872
- }
873
- /**
874
- * @param string $insKey The $_POST key
875
- * @return mixed|null
876
- */
877
- protected function fetchCookie( $insKey ) {
878
- if ( function_exists( 'filter_input' ) && defined( 'INPUT_COOKIE' ) ) {
879
- return filter_input( INPUT_COOKIE, $insKey );
880
- }
881
- return $this->arrayFetch( $_COOKIE, $insKey );
882
- }
883
-
884
- /**
885
- * @param array $inaArray
886
- * @param string $insKey The array key
887
- * @return mixed|null
888
- */
889
- protected function arrayFetch( &$inaArray, $insKey ) {
890
- if ( empty( $inaArray ) ) {
891
- return null;
892
- }
893
- if ( !isset( $inaArray[$insKey] ) ) {
894
- return null;
895
- }
896
- return $inaArray[$insKey];
897
- }
898
-
899
- /**
900
- * Performs a wp_die() but lets us do something first.
901
- */
902
- protected function doWpDie( $insText = '' ) {
903
- wp_die( $insText );
904
- exit();
905
- }
906
-
907
- public function onWpAdminBar() {
908
- $aNodes = $this->getAdminBarNodes();
909
- foreach( $aNodes as $aNode ) {
910
- $this->addAdminBarNode( $aNode );
911
- }
912
- }
913
-
914
- protected function getAdminBarNodes() { }
915
 
916
- protected function addAdminBarNode( $aNode ) {
917
- global $wp_admin_bar;
918
-
919
- if ( isset( $aNode['children'] ) ) {
920
- $aChildren = $aNode['children'];
921
- unset( $aNode['children'] );
922
- }
923
- $wp_admin_bar->add_node( $aNode );
924
-
925
- if ( !empty($aChildren) ) {
926
- foreach( $aChildren as $aChild ) {
927
- $aChild['parent'] = $aNode['id'];
928
- $this->addAdminBarNode( $aChild );
929
  }
930
  }
931
  }
932
 
933
- protected function getPluginLogoUrl16() {
934
- return $this->getImageUrl( 'pluginlogo_16x16.png' );
935
- }
936
-
937
- protected function getPluginLogoUrl32() {
938
- return $this->getImageUrl( 'pluginlogo_32x32.png' );
939
- }
940
-
941
- /**
942
- */
943
- protected function loadDataProcessor() {
944
- require_once( dirname(__FILE__) . '/icwp-data-processor.php' );
945
- }
946
-
947
- }//CLASS
948
-
949
  endif;
1
  <?php
2
 
3
+ require_once( dirname(__FILE__).ICWP_DS.'icwp-foundation.php' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
+ if ( !class_exists('ICWP_Pure_Base_V6') ):
 
6
 
7
+ class ICWP_Pure_Base_V6 extends ICWP_WPSF_Foundation {
 
 
 
 
 
 
 
 
8
 
9
+ /**
10
+ * @var ICWP_WPSF_Plugin_Controller
11
+ */
12
+ protected $oPluginController;
 
 
 
 
 
 
 
 
 
13
 
14
+ protected $fShowMarketing;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
+ public function __construct( ICWP_WPSF_Plugin_Controller $oPluginController ) {
 
 
 
 
 
 
17
 
18
+ // All core values of the plugin are derived from the values stored in this value object.
19
+ $this->oPluginController = $oPluginController;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
+ // add_action( 'plugins_loaded', array( $this, 'onWpPluginsLoaded' ) );
22
+ // add_action( 'init', array( $this, 'onWpInit' ), 0 );
23
+ if ( $this->getController()->getIsValidAdminArea( false ) ) {
24
+ add_action( 'admin_init', array( $this, 'onWpAdminInit' ) );
25
+ add_action( 'admin_menu', array( $this, 'onWpAdminMenu' ) );
26
+ add_action( 'network_admin_menu', array( $this, 'onWpAdminMenu' ) );
27
+ add_action( 'plugin_action_links', array( $this, 'onWpPluginActionLinks' ), 10, 4 );
28
+ // add_action( 'wp_before_admin_bar_render', array( $this, 'onWpAdminBar' ), 1, 9999 );
29
+ }
30
+ $this->registerActivationHooks();
31
+ }
32
+
33
+ /**
34
+ * @return ICWP_WPSF_Plugin_Controller
35
+ */
36
+ public function getController() {
37
+ return $this->oPluginController;
38
+ }
39
+
40
+ /**
41
+ * Returns this unique plugin prefix
42
+ *
43
+ * @param string $sGlue
44
+ * @return string
45
+ */
46
+ public function getPluginPrefix( $sGlue = '-' ) {
47
+ return $this->getController()->getPluginPrefix( $sGlue );
48
+ }
49
+
50
+ /**
51
+ * Will prefix and return any string with the unique plugin prefix.
52
+ *
53
+ * @param string $sSuffix
54
+ * @param string $sGlue
55
+ * @return string
56
+ */
57
+ public function doPluginPrefix( $sSuffix = '', $sGlue = '-' ) {
58
+ return $this->getController()->doPluginPrefix( $sSuffix, $sGlue );
59
+ }
60
+
61
+ /**
62
+ * Registers the plugins activation, deactivate and uninstall hooks.
63
+ */
64
+ protected function registerActivationHooks() {
65
+ register_activation_hook( $this->getController()->getRootFile(), array( $this, 'onWpActivatePlugin' ) );
66
+ register_deactivation_hook( $this->getController()->getRootFile(), array( $this, 'onWpDeactivatePlugin' ) );
67
+ // register_uninstall_hook( $this->oPluginVo->getRootFile(), array( $this, 'onWpUninstallPlugin' ) );
68
+ }
69
+
70
+ /**
71
+ * This is the path to the main plugin file relative to the WordPress plugins directory.
72
+ *
73
+ * @return string
74
+ */
75
+ public function getPluginBaseFile() {
76
+ return $this->getController()->getPluginBaseFile();
77
+ }
78
+
79
+ /**
80
+ * @param boolean $fHasPermission
81
+ * @return boolean
82
+ */
83
+ public function hasPermissionToView( $fHasPermission = true ) {
84
+ return $this->hasPermissionToSubmit( $fHasPermission );
85
+ }
86
+
87
+ /**
88
+ * @param boolean $fHasPermission
89
+ * @return boolean
90
+ */
91
+ public function hasPermissionToSubmit( $fHasPermission = true ) {
92
+ // first a basic admin check
93
+ return $fHasPermission && is_super_admin() && current_user_can( $this->getController()->getBasePermissions() );
94
+ }
95
+
96
+ /**
97
+ * @param string $sView
98
+ * @param array $aData
99
+ * @return bool
100
+ */
101
+ protected function display( $sView, $aData = array() ) {
102
+ $sFile = $this->getController()->getViewPath( $sView );
103
+
104
+ if ( !is_file( $sFile ) ) {
105
+ echo "View not found: ".$sFile;
106
+ return false;
107
+ }
108
 
109
+ if ( count( $aData ) > 0 ) {
110
+ extract( $aData, EXTR_PREFIX_ALL, $this->getController()->getParentSlug() ); //slug being 'icwp'
111
+ }
112
 
113
+ ob_start();
114
+ include( $sFile );
115
+ $sContents = ob_get_contents();
116
+ ob_end_clean();
117
 
118
+ echo $sContents;
119
+ return true;
 
 
 
 
 
 
120
  }
 
 
 
 
121
 
122
+ public function onWpAdminInit() {
123
+ //Do Plugin-Specific Admin Work
124
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueuePluginGlobalAdminCss' ), 99 );
125
+ if ( $this->getIsPage_PluginAdmin() ) {
126
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueueBootstrapLegacyAdminCss' ), 99 );
127
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueuePluginAdminCss' ), 99 );
128
+ }
 
 
 
 
 
129
  }
130
 
131
+ public function onWpAdminMenu() {
132
+ if ( !$this->getController()->getIsValidAdminArea() ) {
133
+ return true;
134
+ }
135
+ $this->createMenu();
136
+ }
137
+
138
+ protected function createMenu() {
139
+ $oPluginController = $this->getController();
140
+
141
+ $sFullParentMenuId = $this->getPluginPrefix();
142
+ add_menu_page(
143
+ $oPluginController->getHumanName(),
144
+ $oPluginController->getAdminMenuTitle(),
145
+ $oPluginController->getBasePermissions(),
146
+ $sFullParentMenuId,
147
+ array( $this, 'onDisplayAll' ),
148
+ $this->getController()->getPluginUrl_Image( 'pluginlogo_16x16.png' )
149
+ );
150
+ //Create and Add the submenu items
151
+
152
+ // allow for any plugin menu items that don't come from filters
153
+ add_filter( $this->doPluginPrefix( 'filter_plugin_submenu_items' ), array( $this, 'filter_addExtraAdminMenuItems' ) );
154
+
155
+ $aPluginMenuItems = apply_filters( $this->doPluginPrefix( 'filter_plugin_submenu_items' ), array() );
156
+ if ( !empty( $aPluginMenuItems ) ) {
157
+ foreach ( $aPluginMenuItems as $sMenuTitle => $aMenu ) {
158
+ list( $sMenuItemText, $sMenuItemId, $aMenuCallBack ) = $aMenu;
159
+ add_submenu_page(
160
+ $sFullParentMenuId,
161
+ $sMenuTitle,
162
+ $sMenuItemText,
163
+ $oPluginController->getBasePermissions(),
164
+ $sMenuItemId,
165
+ $aMenuCallBack
166
+ );
167
+ }
168
+ }
169
+ $this->fixSubmenu();
170
  }
171
 
172
+ /**
173
+ * @param array $aItems
174
+ * @return array
175
+ */
176
+ public function filter_addExtraAdminMenuItems( $aItems ) {
177
+ return $aItems;
178
  }
179
 
180
+ protected function fixSubmenu() {
181
+ global $submenu;
182
+ $sFullParentMenuId = $this->getPluginPrefix();
183
+ if ( isset( $submenu[$sFullParentMenuId] ) ) {
184
+ unset( $submenu[$sFullParentMenuId][0] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  }
186
  }
 
 
 
 
 
 
 
 
187
 
188
+ /**
189
+ * Displaying all views now goes through this central function and we work out
190
+ * what to display based on the name of current hook/filter being processed.
191
+ */
192
+ public function onDisplayAll() { }
 
 
193
 
194
+ protected function getBaseDisplayData() {
195
+ $oWp = $this->loadWpFunctionsProcessor();
196
+ return array(
197
+ 'plugin_url' => $this->getController()->getPluginUrl(),
198
+ 'var_prefix' => $this->getController()->getOptionStoragePrefix(),
199
+ 'sPluginName' => $this->getController()->getHumanName(),
200
+ 'fShowAds' => $this->isShowMarketing(),
201
+ 'nonce_field' => $this->getPluginPrefix(),
202
+ 'form_action' => 'admin.php?page='.$oWp->getCurrentWpAdminPage()
203
+ );
 
204
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
 
206
+ /**
207
+ * @return bool
208
+ */
209
+ protected function getIsPage_PluginMainDashboard() {
210
+ $oWp = $this->loadWpFunctionsProcessor();
211
+ return ( $oWp->getCurrentWpAdminPage() == $this->getPluginPrefix() );
 
 
 
 
 
 
 
 
 
 
 
212
  }
 
 
213
 
214
+ /**
215
+ * @return bool
216
+ */
217
+ protected function getIsPage_PluginAdmin() {
218
+ $oWp = $this->loadWpFunctionsProcessor();
219
+ return ( strpos( $oWp->getCurrentWpAdminPage(), $this->getPluginPrefix() ) === 0 );
220
+ }
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
+ /**
223
+ * @return bool
224
+ */
225
+ protected function isShowMarketing() {
226
 
227
+ if ( isset($this->fShowMarketing) ) {
228
+ return $this->fShowMarketing;
 
 
 
 
 
229
  }
230
+ $this->fShowMarketing = true;
231
+ if ( class_exists( 'Worpit_Plugin' ) ) {
232
+ if ( method_exists( 'Worpit_Plugin', 'IsLinked' ) ) {
233
+ $this->fShowMarketing = !Worpit_Plugin::IsLinked();
234
+ }
235
+ else if ( function_exists( 'get_option' )
236
  && get_option( Worpit_Plugin::$VariablePrefix.'assigned' ) == 'Y'
237
  && get_option( Worpit_Plugin::$VariablePrefix.'assigned_to' ) != '' ) {
238
+
239
+ $this->fShowMarketing = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  }
241
  }
242
+ return $this->fShowMarketing ;
243
+ }
244
+
245
+ /**
246
+ * On the plugins listing page, hides the edit and deactivate links
247
+ * for this plugin based on permissions
248
+ *
249
+ * @see ICWP_Pure_Base_V1::onWpPluginActionLinks()
250
+ */
251
+ public function onWpPluginActionLinks( $aActionLinks, $sPluginFile ) {
252
+
253
+ if ( $sPluginFile == $this->getPluginBaseFile() ) {
254
+ if ( !$this->hasPermissionToSubmit() ) {
255
+ if ( array_key_exists( 'edit', $aActionLinks ) ) {
256
+ unset( $aActionLinks['edit'] );
257
+ }
258
+ if ( array_key_exists( 'deactivate', $aActionLinks ) ) {
259
+ unset( $aActionLinks['deactivate'] );
260
+ }
261
+ }
262
 
263
+ $sSettingsLink = sprintf( '<a href="%s">%s</a>', $this->getController()->getPluginUrl_AdminPage(), 'Dashboard' ); ;
264
+ array_unshift( $aActionLinks, $sSettingsLink );
265
+ }
266
+ return $aActionLinks;
267
  }
 
 
268
 
269
+ /**
270
+ * @return bool
271
+ */
272
+ protected function getShowAdminNotices() {
 
 
273
  return true;
274
  }
275
 
276
+ /**
277
+ * Updates the current (or supplied user ID) user meta data with the version of the plugin
278
+ *
279
+ * @param $nId
280
+ * @param $sValue
281
+ */
282
+ protected function updateTranslationNoticeShownUserMeta( $nId = '', $sValue = 'Y' ) {
283
+ $oWp = $this->loadWpFunctionsProcessor();
284
+ $oWp->updateUserMeta( $this->getController()->doPluginOptionPrefix( 'plugin_translation_notice' ), $sValue, $nId );
 
 
 
 
285
  }
 
 
 
286
 
287
+ /**
288
+ * Updates the current (or supplied user ID) user meta data with the version of the plugin
289
+ *
290
+ * @param $nId
291
+ * @param $sValue
292
+ */
293
+ protected function updateMailingListSignupShownUserMeta( $nId = '', $sValue = 'Y' ) {
294
+ $oWp = $this->loadWpFunctionsProcessor();
295
+ $oWp->updateUserMeta( $this->getController()->doPluginOptionPrefix( 'plugin_mailing_list_signup' ), $sValue, $nId );
296
  }
297
 
298
+ /**
299
+ * Updates the current (or supplied user ID) user meta data with the version of the plugin
300
+ *
301
+ * @param integer $nId
302
+ */
303
+ protected function updateVersionUserMeta( $nId = null ) {
304
+ $oWp = $this->loadWpFunctionsProcessor();
305
+ $oWp->updateUserMeta( $this->getController()->doPluginOptionPrefix( 'current_version' ), $this->getController()->getVersion(), $nId );
 
 
 
 
 
306
  }
 
 
 
307
 
308
+ public function enqueueBootstrapAdminCss() {
309
+ $sUnique = $this->doPluginPrefix( 'bootstrap_wpadmin_css' );
310
+ wp_register_style( $sUnique, $this->getController()->getPluginUrl_Css( 'bootstrap-wpadmin.css' ), false, $this->getController()->getVersion() );
311
+ wp_enqueue_style( $sUnique );
 
 
 
312
  }
 
313
 
314
+ public function enqueueBootstrapLegacyAdminCss() {
315
+ $sUnique = $this->doPluginPrefix( 'bootstrap_wpadmin_legacy_css' );
316
+ wp_register_style( $sUnique, $this->getController()->getPluginUrl_Css( 'bootstrap-wpadmin-legacy.css' ), false, $this->getController()->getVersion() );
317
+ wp_enqueue_style( $sUnique );
318
 
319
+ $sUnique = $this->doPluginPrefix( 'bootstrap_wpadmin_css_fixes' );
320
+ wp_register_style( $sUnique, $this->getController()->getPluginUrl_Css('bootstrap-wpadmin-fixes.css'), array( $this->doPluginPrefix( 'bootstrap_wpadmin_legacy_css' ) ), $this->getController()->getVersion() );
321
+ wp_enqueue_style( $sUnique );
 
 
 
 
 
322
  }
 
323
 
324
+ public function enqueuePluginAdminCss() {
325
+ $sUnique = $this->doPluginPrefix( 'plugin_css' );
326
+ wp_register_style( $sUnique, $this->getController()->getPluginUrl_Css('plugin.css'), array( $this->doPluginPrefix( 'bootstrap_wpadmin_css_fixes' ) ), $this->getController()->getVersion().rand() );
327
+ wp_enqueue_style( $sUnique );
 
 
 
 
328
  }
329
 
330
+ public function enqueuePluginGlobalAdminCss() {
331
+ $sUnique = $this->doPluginPrefix( 'global_plugin_css' );
332
+ wp_register_style( $sUnique, $this->getController()->getPluginUrl_Css('global-plugin.css'), false, $this->getController()->getVersion().rand() );
333
+ wp_enqueue_style( $sUnique );
334
  }
 
335
 
336
+ public function onWpActivatePlugin() { }
 
 
 
 
 
 
 
 
337
 
338
+ public function onWpDeactivatePlugin() {
339
+ if ( current_user_can( $this->getController()->getBasePermissions() ) ) {
340
+ do_action( $this->doPluginPrefix( 'delete_plugin' ) );
341
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  }
 
 
 
 
 
 
 
 
343
 
344
+ /**
345
+ */
346
+ public function onWpAdminBar() {
347
+ $aNodes = $this->getAdminBarNodes();
348
+ if ( !is_array( $aNodes ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
  return;
350
  }
351
+ foreach( $aNodes as $aNode ) {
352
+ $this->addAdminBarNode( $aNode );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  }
354
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
 
356
+ protected function getAdminBarNodes() { }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
 
358
+ protected function addAdminBarNode( $aNode ) {
359
+ global $wp_admin_bar;
 
 
 
 
 
 
 
 
 
 
360
 
361
+ if ( isset( $aNode['children'] ) ) {
362
+ $aChildren = $aNode['children'];
363
+ unset( $aNode['children'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  }
365
+ $wp_admin_bar->add_node( $aNode );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
366
 
367
+ if ( !empty($aChildren) ) {
368
+ foreach( $aChildren as $aChild ) {
369
+ $aChild['parent'] = $aNode['id'];
370
+ $this->addAdminBarNode( $aChild );
371
+ }
 
 
 
 
 
 
 
 
372
  }
373
  }
374
  }
375
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  endif;
src/icwp-wpfilesystem.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
- *
6
  * Version: 2013-11-19
7
  *
8
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -17,287 +17,335 @@
17
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
  */
19
 
20
- if ( !class_exists('ICWP_WpFilesystem_V2') ):
21
-
22
- class ICWP_WpFilesystem_V2 {
23
-
24
- /**
25
- * @var ICWP_WpFilesystem_V2
26
- */
27
- protected static $oInstance = NULL;
28
-
29
- /**
30
- * @var object
31
- */
32
- protected $m_oWpFilesystem = null;
33
-
34
- /**
35
- * @var string
36
- */
37
- protected $m_sWpConfigPath = null;
38
-
39
- /**
40
- * @return ICWP_WpFilesystem_V2
41
- */
42
- public static function GetInstance() {
43
- if ( is_null( self::$oInstance ) ) {
44
- self::$oInstance = new self();
 
 
45
  }
46
- return self::$oInstance;
47
- }
48
-
49
- public function __construct() {
50
- $this->initFileSystem();
51
- // $this->setWpConfigPath();
52
- }
53
-
54
- /**
55
- * @param $sPath
56
- * @return boolean true/false whether file/directory exists
57
- */
58
- public function exists( $sPath ) {
59
- return $this->fileAction( 'file_exists', $sPath );
60
- }
61
-
62
- protected function setWpConfigPath() {
63
- $this->m_sWpConfigPath = ABSPATH.'wp-config.php';
64
- if ( !$this->exists($this->m_sWpConfigPath) ) {
65
- $this->m_sWpConfigPath = ABSPATH.'..'.ICWP_DS.'wp-config.php';
66
- if ( !$this->exists($this->m_sWpConfigPath) ) {
67
- $this->m_sWpConfigPath = false;
68
  }
 
69
  }
70
- }
71
 
72
- protected function initFileSystem() {
73
- if ( is_null( $this->m_oWpFilesystem ) ) {
74
- require_once(ABSPATH . 'wp-admin/includes/file.php');
75
- WP_Filesystem();
76
- global $wp_filesystem;
77
- if ( isset( $wp_filesystem ) && is_object( $wp_filesystem ) ) {
78
- $this->m_oWpFilesystem = &$wp_filesystem;
 
 
79
  }
80
- else {
81
- $this->m_oWpFilesystem = false;
 
 
 
 
 
 
 
 
 
82
  }
83
- }
84
- }
85
-
86
- public function getContent_WpConfig() {
87
- return $this->getFileContent( $this->m_sWpConfigPath );
88
- }
89
-
90
- public function putContent_WpConfig( $insContent ) {
91
- return $this->putFileContent( $this->m_sWpConfigPath, $insContent );
92
- }
93
-
94
-
95
- /**
96
- * @return string
97
- */
98
- public function getWpConfigPath() {
99
- return $this->m_sWpConfigPath;
100
- }
101
-
102
- public function getUrl( $insUrl ) {
103
- $mResult = wp_remote_get( $insUrl );
104
- if ( is_wp_error( $mResult ) ) {
105
  return false;
106
  }
107
- if ( !isset( $mResult['response']['code'] ) || $mResult['response']['code'] != 200 ) {
108
- return false;
 
 
 
 
 
 
 
109
  }
110
- return $mResult;
111
- }
112
-
113
- public function getUrlContent( $insUrl ) {
114
-
115
- $aResponse = $this->getUrl( $insUrl );
116
- if ( !$aResponse ) {
117
- return false;
118
  }
119
- return $aResponse['body'];
120
- }
121
-
122
- public function getCanWpRemoteGet() {
123
- $aUrlsToTest = array(
124
- 'https://www.microsoft.com',
125
- 'https://www.google.com',
126
- 'https://www.facebook.com'
127
- );
128
- foreach( $aUrlsToTest as $sUrl ) {
129
- if ( $this->getUrl( $sUrl ) !== false ) {
130
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
 
132
  }
133
- return false;
134
- }
135
-
136
- public function getCanDiskWrite() {
137
- $sFilePath = dirname( __FILE__ ).'/testfile.'.rand().'txt';
138
- $sContents = "Testing icwp file read and write.";
139
-
140
- // Write, read, verify, delete.
141
- if ( $this->putFileContent( $sFilePath, $sContents ) ) {
142
- $sFileContents = $this->getFileContent( $sFilePath );
143
- if ( !is_null( $sFileContents ) && $sFileContents === $sContents ) {
144
- return $this->deleteFile( $sFilePath );
145
  }
 
146
  }
147
- return false;
148
- }
149
 
150
- /**
151
- * @param $sFilePath
152
- * @return int|null
153
- */
154
- public function getModifiedTime( $sFilePath ) {
155
- return $this->getTime($sFilePath, 'modified');
156
- }
 
 
 
 
 
 
157
 
158
- /**
159
- * @param $sFilePath
160
- * @return int|null
161
- */
162
- public function getAccessedTime( $sFilePath ) {
163
- return $this->getTime($sFilePath, 'accessed');
164
- }
165
 
166
- /**
167
- * @param $sFilePath
168
- * @param string $sProperty
169
- * @return int|null
170
- */
171
- public function getTime( $sFilePath, $sProperty = 'modified' ) {
 
 
 
172
 
173
- if ( !$this->exists($sFilePath) ) {
174
- return null;
 
 
 
 
175
  }
176
 
177
- $fUseWp = $this->m_oWpFilesystem ? true : false;
 
 
 
 
 
 
178
 
179
- switch ( $sProperty ) {
 
 
 
 
 
180
 
181
- case 'modified' :
182
- return $fUseWp? $this->m_oWpFilesystem->mtime( $sFilePath ) : filemtime( $sFilePath );
183
- break;
184
- case 'accessed' :
185
- return $fUseWp? $this->m_oWpFilesystem->atime( $sFilePath ) : fileatime( $sFilePath );
186
- break;
187
- default:
188
  return null;
189
- break;
190
- }
191
- }
192
 
193
- /**
194
- * @param string $insFilePath
195
- * @return NULL|boolean
196
- */
197
- public function getCanReadWriteFile( $insFilePath ) {
198
- if ( !file_exists( $insFilePath ) ) {
199
- return null;
200
- }
201
-
202
- $nFileSize = filesize( $insFilePath );
203
- if ( $nFileSize === 0 ) {
204
- return null;
205
- }
206
 
207
- $sFileContent = $this->getFileContent( $insFilePath );
208
- if ( empty( $sFileContent ) ) {
209
- return false; //can't even read the file!
210
- }
211
- return $this->putFileContent( $insFilePath, $sFileContent );
212
- }
213
-
214
- /**
215
- * @param string $sFilePath
216
- * @return string|null
217
- */
218
- public function getFileContent( $sFilePath ) {
219
- if ( !$this->exists( $sFilePath ) ) {
220
- return null;
221
- }
222
- if ( $this->m_oWpFilesystem ) {
223
- return $this->m_oWpFilesystem->get_contents( $sFilePath );
224
- }
225
- else if ( function_exists('file_get_contents') ) {
226
- return file_get_contents( $sFilePath );
227
  }
228
- return null;
229
- }
230
-
231
- /**
232
- * @param string $sFilePath
233
- * @param string $sContents
234
- * @return boolean
235
- */
236
- public function putFileContent( $sFilePath, $sContents ) {
237
- if ( $this->m_oWpFilesystem ) {
238
- return $this->m_oWpFilesystem->put_contents( $sFilePath, $sContents, FS_CHMOD_FILE );
 
 
 
 
 
 
 
 
 
239
  }
240
- else if ( file_put_contents( $sFilePath, $sContents ) === false ) {
241
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  }
243
- return true;
244
- }
245
 
246
- /**
247
- * @param $insFilePath
248
- * @return boolean
249
- */
250
- public function deleteFile( $insFilePath ) {
251
- if ( !$this->exists( $insFilePath ) ) {
 
 
 
 
 
 
 
 
252
  return null;
253
  }
254
- if ( $this->m_oWpFilesystem ) {
255
- return $this->m_oWpFilesystem->delete( $insFilePath );
256
- }
257
- else {
258
- return unlink( $insFilePath );
259
- }
260
- }
261
 
262
- public function fileAction( $insFunctionName, $inaParams ) {
263
- $aFunctionMap = array(
264
- 'file_exists' => 'exists',
265
- 'touch' => 'touch'
266
- );
267
-
268
- if ( !is_array($inaParams) ) {
269
- $inaParams = array($inaParams);
270
- }
271
-
272
- if ( !$this->m_oWpFilesystem ) {
273
- if ( function_exists( $insFunctionName ) ) {
274
- call_user_func_array( $insFunctionName, $inaParams );
275
  }
276
- else {
277
- return false;
 
 
 
 
 
 
 
 
 
 
278
  }
 
279
  }
280
- if ( !array_key_exists($insFunctionName, $aFunctionMap) ) {
281
- return false;
 
 
 
 
 
 
 
 
 
 
282
  }
283
- $sWpFunctionName = $aFunctionMap[$insFunctionName];
284
- $sResult = call_user_func_array( array($this->m_oWpFilesystem, $sWpFunctionName), $inaParams );
285
- return $sResult;
286
- }
287
- }
288
- endif;
289
 
290
- if ( !class_exists('ICWP_WpFilesystem_WPSF') ):
 
 
 
 
 
 
 
291
 
292
- class ICWP_WpFilesystem_WPSF extends ICWP_WpFilesystem_V2 {
293
  /**
294
- * @return ICWP_WpFilesystem_WPSF
295
  */
296
- public static function GetInstance() {
297
- if ( is_null( self::$oInstance ) ) {
298
- self::$oInstance = new self();
 
 
 
 
 
 
 
 
299
  }
300
- return self::$oInstance;
301
  }
302
  }
303
- endif;
2
  /**
3
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
+ *
6
  * Version: 2013-11-19
7
  *
8
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
  */
19
 
20
+ if ( !class_exists('ICWP_WPSF_WpFilesystem') ):
21
+
22
+ class ICWP_WPSF_WpFilesystem {
23
+
24
+ /**
25
+ * @var ICWP_WPSF_WpFilesystem
26
+ */
27
+ protected static $oInstance = NULL;
28
+
29
+ /**
30
+ * @var WP_Filesystem
31
+ */
32
+ protected $oWpfs = null;
33
+
34
+ /**
35
+ * @var string
36
+ */
37
+ protected $m_sWpConfigPath = null;
38
+
39
+ /**
40
+ * @return ICWP_WPSF_WpFilesystem
41
+ */
42
+ public static function GetInstance() {
43
+ if ( is_null( self::$oInstance ) ) {
44
+ self::$oInstance = new self();
45
+ }
46
+ return self::$oInstance;
47
  }
48
+
49
+ /**
50
+ * @param string $sBase
51
+ * @param string $sPath
52
+ * @return string
53
+ */
54
+ public function pathJoin( $sBase, $sPath ) {
55
+ return rtrim( $sBase, ICWP_DS ).ICWP_DS.ltrim( $sPath, ICWP_DS );
56
+ }
57
+
58
+ /**
59
+ * @param $sFilePath
60
+ * @return boolean|null true/false whether file/directory exists
61
+ */
62
+ public function exists( $sFilePath ) {
63
+ $oFs = $this->getWpfs();
64
+ if ( $oFs ) {
65
+ return $oFs->exists( $sFilePath );
 
 
 
 
66
  }
67
+ return function_exists( 'file_exists' ) ? file_exists( $sFilePath ) : null;
68
  }
 
69
 
70
+ /**
71
+ * @param string $sNeedle
72
+ * @param string $sDir
73
+ * @param boolean $fCaseSensitive
74
+ * @return boolean
75
+ */
76
+ public function fileExistsInDir( $sNeedle, $sDir, $fCaseSensitive = true ) {
77
+ if ( $fCaseSensitive ) {
78
+ return $this->exists( $this->pathJoin( $sDir, $sNeedle ) );
79
  }
80
+ $sNeedle = strtolower( $sNeedle );
81
+ if ( $oHandle = opendir( $sDir ) ) {
82
+
83
+ while ( false !== ( $sFileEntry = readdir( $oHandle ) ) ) {
84
+ if ( !$this->isFile( $this->pathJoin( $sDir, $sFileEntry ) ) ) {
85
+ continue;
86
+ }
87
+ if ( $sNeedle == strtolower( $sFileEntry ) ) {
88
+ return true;
89
+ }
90
+ }
91
  }
92
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  return false;
94
  }
95
+
96
+ protected function setWpConfigPath() {
97
+ $this->m_sWpConfigPath = ABSPATH.'wp-config.php';
98
+ if ( !$this->exists($this->m_sWpConfigPath) ) {
99
+ $this->m_sWpConfigPath = ABSPATH.'..'.ICWP_DS.'wp-config.php';
100
+ if ( !$this->exists($this->m_sWpConfigPath) ) {
101
+ $this->m_sWpConfigPath = false;
102
+ }
103
+ }
104
  }
105
+
106
+ public function getContent_WpConfig() {
107
+ return $this->getFileContent( $this->m_sWpConfigPath );
 
 
 
 
 
108
  }
109
+
110
+ /**
111
+ * @param string $sContent
112
+ * @return bool
113
+ */
114
+ public function putContent_WpConfig( $sContent ) {
115
+ return $this->putFileContent( $this->m_sWpConfigPath, $sContent );
116
+ }
117
+
118
+ /**
119
+ * @param string $sUrl
120
+ * @param boolean $fSecure
121
+ * @return boolean
122
+ */
123
+ public function getIsUrlValid( $sUrl, $fSecure = false ) {
124
+ $sSchema = $fSecure? 'https://' : 'http://';
125
+ $sUrl = ( strpos( $sUrl, 'http' ) !== 0 )? $sSchema.$sUrl : $sUrl;
126
+ return ( $this->getUrl( $sUrl ) != false );
127
+ }
128
+
129
+ /**
130
+ * @return string
131
+ */
132
+ public function getWpConfigPath() {
133
+ return $this->m_sWpConfigPath;
134
+ }
135
+
136
+ /**
137
+ * @param string $sUrl
138
+ * @return bool
139
+ */
140
+ public function getUrl( $sUrl ) {
141
+ $mResult = wp_remote_get( $sUrl );
142
+ if ( is_wp_error( $mResult ) ) {
143
+ return false;
144
+ }
145
+ if ( !isset( $mResult['response']['code'] ) || $mResult['response']['code'] != 200 ) {
146
+ return false;
147
  }
148
+ return $mResult;
149
  }
150
+
151
+ /**
152
+ * @param string $sUrl
153
+ * @return bool|string
154
+ */
155
+ public function getUrlContent( $sUrl ) {
156
+ $aResponse = $this->getUrl( $sUrl );
157
+ if ( !$aResponse || !isset( $aResponse['body'] ) ) {
158
+ return false;
 
 
 
159
  }
160
+ return $aResponse['body'];
161
  }
 
 
162
 
163
+ public function getCanWpRemoteGet() {
164
+ $aUrlsToTest = array(
165
+ 'https://www.microsoft.com',
166
+ 'https://www.google.com',
167
+ 'https://www.facebook.com'
168
+ );
169
+ foreach( $aUrlsToTest as $sUrl ) {
170
+ if ( $this->getUrl( $sUrl ) !== false ) {
171
+ return true;
172
+ }
173
+ }
174
+ return false;
175
+ }
176
 
177
+ public function getCanDiskWrite() {
178
+ $sFilePath = dirname( __FILE__ ).'/testfile.'.rand().'txt';
179
+ $sContents = "Testing icwp file read and write.";
 
 
 
 
180
 
181
+ // Write, read, verify, delete.
182
+ if ( $this->putFileContent( $sFilePath, $sContents ) ) {
183
+ $sFileContents = $this->getFileContent( $sFilePath );
184
+ if ( !is_null( $sFileContents ) && $sFileContents === $sContents ) {
185
+ return $this->deleteFile( $sFilePath );
186
+ }
187
+ }
188
+ return false;
189
+ }
190
 
191
+ /**
192
+ * @param string $sFilePath
193
+ * @return int|null
194
+ */
195
+ public function getModifiedTime( $sFilePath ) {
196
+ return $this->getTime( $sFilePath, 'modified' );
197
  }
198
 
199
+ /**
200
+ * @param string $sFilePath
201
+ * @return int|null
202
+ */
203
+ public function getAccessedTime( $sFilePath ) {
204
+ return $this->getTime( $sFilePath, 'accessed' );
205
+ }
206
 
207
+ /**
208
+ * @param string $sFilePath
209
+ * @param string $sProperty
210
+ * @return int|null
211
+ */
212
+ public function getTime( $sFilePath, $sProperty = 'modified' ) {
213
 
214
+ if ( !$this->exists( $sFilePath ) ) {
 
 
 
 
 
 
215
  return null;
216
+ }
 
 
217
 
218
+ $oFs = $this->getWpfs();
219
+ switch ( $sProperty ) {
 
 
 
 
 
 
 
 
 
 
 
220
 
221
+ case 'modified' :
222
+ return $oFs? $oFs->mtime( $sFilePath ) : filemtime( $sFilePath );
223
+ break;
224
+ case 'accessed' :
225
+ return $oFs? $oFs->atime( $sFilePath ) : fileatime( $sFilePath );
226
+ break;
227
+ default:
228
+ return null;
229
+ break;
230
+ }
 
 
 
 
 
 
 
 
 
 
231
  }
232
+
233
+ /**
234
+ * @param string $sFilePath
235
+ * @return NULL|boolean
236
+ */
237
+ public function getCanReadWriteFile( $sFilePath ) {
238
+ if ( !file_exists( $sFilePath ) ) {
239
+ return null;
240
+ }
241
+
242
+ $nFileSize = filesize( $sFilePath );
243
+ if ( $nFileSize === 0 ) {
244
+ return null;
245
+ }
246
+
247
+ $sFileContent = $this->getFileContent( $sFilePath );
248
+ if ( empty( $sFileContent ) ) {
249
+ return false; //can't even read the file!
250
+ }
251
+ return $this->putFileContent( $sFilePath, $sFileContent );
252
  }
253
+
254
+ /**
255
+ * @param string $sFilePath
256
+ * @return string|null
257
+ */
258
+ public function getFileContent( $sFilePath ) {
259
+ $sContents = null;
260
+ $oFs = $this->getWpfs();
261
+ if ( $oFs ) {
262
+ $sContents = $oFs->get_contents( $sFilePath );
263
+ }
264
+
265
+ if ( empty( $sContents ) && function_exists( 'file_get_contents' ) ) {
266
+ $sContents = file_get_contents( $sFilePath );
267
+ }
268
+ return $sContents;
269
  }
 
 
270
 
271
+ /**
272
+ * @param string $sFilePath
273
+ * @param string $sContents
274
+ * @return boolean|null
275
+ */
276
+ public function putFileContent( $sFilePath, $sContents ) {
277
+ $oFs = $this->getWpfs();
278
+ if ( $oFs ) {
279
+ return $oFs->put_contents( $sFilePath, $sContents, FS_CHMOD_FILE );
280
+ }
281
+
282
+ if ( function_exists( 'file_put_contents' ) ) {
283
+ return file_put_contents( $sFilePath, $sContents ) !== false;
284
+ }
285
  return null;
286
  }
 
 
 
 
 
 
 
287
 
288
+ /**
289
+ * @param $sFilePath
290
+ * @return boolean|null
291
+ */
292
+ public function deleteFile( $sFilePath ) {
293
+ $oFs = $this->getWpfs();
294
+ if ( $oFs ) {
295
+ return $oFs->delete( $sFilePath );
 
 
 
 
 
296
  }
297
+
298
+ return function_exists( 'unlink' ) ? unlink( $sFilePath ) : null;
299
+ }
300
+
301
+ /**
302
+ * @param $sFilePath
303
+ * @return bool|mixed
304
+ */
305
+ public function isFile( $sFilePath ) {
306
+ $oFs = $this->getWpfs();
307
+ if ( $oFs ) {
308
+ return $oFs->is_file( $sFilePath );
309
  }
310
+ return function_exists( 'is_file' ) ? is_file( $sFilePath ) : null;
311
  }
312
+
313
+ /**
314
+ * @param string $sFilePath
315
+ * @param int $nTime
316
+ * @return bool|mixed
317
+ */
318
+ public function touch( $sFilePath, $nTime ) {
319
+ $oFs = $this->getWpfs();
320
+ if ( $oFs ) {
321
+ return $oFs->touch( $sFilePath, $nTime );
322
+ }
323
+ return function_exists( 'touch' ) ? touch( $sFilePath, $nTime ) : null;
324
  }
 
 
 
 
 
 
325
 
326
+ /**
327
+ */
328
+ protected function getWpfs() {
329
+ if ( is_null( $this->oWpfs ) ) {
330
+ $this->initFileSystem();
331
+ }
332
+ return $this->oWpfs;
333
+ }
334
 
 
335
  /**
 
336
  */
337
+ private function initFileSystem() {
338
+ if ( is_null( $this->oWpfs ) ) {
339
+ require_once( ABSPATH . 'wp-admin'.ICWP_DS.'includes'.ICWP_DS.'file.php' );
340
+ WP_Filesystem();
341
+ global $wp_filesystem;
342
+ if ( isset( $wp_filesystem ) && is_object( $wp_filesystem ) ) {
343
+ $this->oWpfs = $wp_filesystem;
344
+ }
345
+ else {
346
+ $this->oWpfs = false;
347
+ }
348
  }
 
349
  }
350
  }
351
+ endif;
src/icwp-wpfunctions.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
- *
6
  * Version: 2013-08-14_A
7
  *
8
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -17,230 +17,525 @@
17
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
  */
19
 
20
- if ( !class_exists('ICWP_WpFunctions_V4') ):
 
 
21
 
22
- class ICWP_WpFunctions_V4 {
23
 
24
- /**
25
- * @var ICWP_WpFunctions_V4
26
- */
27
- protected static $oInstance = NULL;
28
 
29
- /**
30
- * @return ICWP_WpFunctions_V4
31
- */
32
- public static function GetInstance() {
33
- if ( is_null( self::$oInstance ) ) {
34
- self::$oInstance = new self();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
36
- return self::$oInstance;
37
- }
38
 
39
- /**
40
- * @var string
41
- */
42
- protected $m_sWpVersion;
43
-
44
- /**
45
- * @var boolean
46
- */
47
- protected $fIsMultisite;
48
-
49
- public function __construct() {}
50
-
51
- /**
52
- * @param string $insPluginFile
53
- * @return boolean|stdClass
54
- */
55
- public function getIsPluginUpdateAvailable( $insPluginFile ) {
56
- $aUpdates = $this->getWordpressUpdates();
57
- if ( empty( $aUpdates ) ) {
58
  return false;
59
  }
60
- if ( isset( $aUpdates[ $insPluginFile ] ) ) {
61
- return $aUpdates[ $insPluginFile ];
 
 
 
 
 
 
 
 
 
 
 
62
  }
63
- return false;
64
- }
65
 
66
- public function getPluginUpgradeLink( $insPluginFile ) {
67
- $sUrl = self_admin_url( 'update.php' ) ;
68
- $aQueryArgs = array(
69
- 'action' => 'upgrade-plugin',
70
- 'plugin' => urlencode( $insPluginFile ),
71
- '_wpnonce' => wp_create_nonce( 'upgrade-plugin_' . $insPluginFile )
72
- );
73
- return add_query_arg( $aQueryArgs, $sUrl );
74
- }
75
-
76
- public function getWordpressUpdates() {
77
- $oCurrent = $this->getTransient( 'update_plugins' );
78
- return $oCurrent->response;
79
- }
80
-
81
- /**
82
- * The full plugin file to be upgraded.
83
- *
84
- * @param string $insPluginFile
85
- * @return boolean
86
- */
87
- public function doPluginUpgrade( $insPluginFile ) {
88
-
89
- if ( !$this->getIsPluginUpdateAvailable($insPluginFile)
90
- || ( isset( $GLOBALS['pagenow'] ) && $GLOBALS['pagenow'] == 'update.php' ) ) {
91
- return true;
92
- }
93
- $sUrl = $this->getPluginUpgradeLink( $insPluginFile );
94
- wp_redirect( $sUrl );
95
- exit();
96
- }
97
- /**
98
- * @param string $insKey
99
- * @return object
100
- */
101
- protected function getTransient( $insKey ) {
102
-
103
- // TODO: Handle multisite
104
-
105
- if ( version_compare( $this->getWordpressVersion(), '2.7.9', '<=' ) ) {
106
- return get_option( $insKey );
107
- }
108
-
109
- if ( function_exists( 'get_site_transient' ) ) {
110
- return get_site_transient( $insKey );
111
- }
112
-
113
- if ( version_compare( $this->getWordpressVersion(), '2.9.9', '<=' ) ) {
114
- return apply_filters( 'transient_'.$insKey, get_option( '_transient_'.$insKey ) );
115
- }
116
-
117
- return apply_filters( 'site_transient_'.$insKey, get_option( '_site_transient_'.$insKey ) );
118
- }
119
-
120
- /**
121
- * @return string
122
- */
123
- public function getWordpressVersion() {
124
- global $wp_version;
125
-
126
- if ( empty( $this->m_sWpVersion ) ) {
127
- $sVersionFile = ABSPATH.WPINC.'/version.php';
128
- $sVersionContents = file_get_contents( $sVersionFile );
129
-
130
- if ( preg_match( '/wp_version\s=\s\'([^(\'|")]+)\'/i', $sVersionContents, $aMatches ) ) {
131
- $this->m_sWpVersion = $aMatches[1];
132
- }
133
- }
134
- return empty( $this->m_sWpVersion )? $wp_version : $this->m_sWpVersion;
135
- }
136
 
137
- /**
138
- * @param string $sParams
139
- */
140
- public function redirectToLogin( $sParams = '' ) {
141
- $sParams = empty( $sParams ) ? '' : '?'.$sParams;
142
- header( "Location: ".site_url().'/wp-login.php'.$sParams );
143
- exit();
144
- }
145
- /**
146
- */
147
- public function redirectToAdmin() {
148
- $this->doRedirect( is_multisite()? get_admin_url() : admin_url() );
149
- }
150
- /**
151
- */
152
- public function redirectToHome() {
153
- $this->doRedirect( home_url() );
154
- }
155
 
156
- public function doRedirect( $sUrl ) {
157
- wp_safe_redirect( $sUrl );
158
- exit();
159
- }
 
 
 
160
 
161
- /**
162
- * @return string
163
- */
164
- public function getSiteName() {
165
- return function_exists( 'get_bloginfo' )? get_bloginfo('name') : 'WordPress Site';
166
- }
167
- /**
168
- * @return string
169
- */
170
- public function getSiteAdminEmail() {
171
- return function_exists( 'get_bloginfo' )? get_bloginfo('admin_email') : '';
172
- }
 
173
 
174
- /**
175
- * @param string $sRedirectUrl
176
- */
177
- public function logoutUser( $sRedirectUrl = '' ) {
178
- empty( $sRedirectUrl ) ? wp_logout() : wp_logout_url( $sRedirectUrl );
179
- }
 
 
 
 
 
 
 
180
 
181
- /**
182
- * @return bool
183
- */
184
- public function isMultisite() {
185
- if ( !isset( $this->fIsMultisite ) ) {
186
- $this->fIsMultisite = function_exists( 'is_multisite' ) && is_multisite();
 
 
 
 
 
 
187
  }
188
- return $this->fIsMultisite;
189
- }
190
 
191
- /**
192
- * @param string $sKey
193
- * @param $sValue
194
- * @return mixed
195
- */
196
- public function addOption( $sKey, $sValue ) {
197
- return $this->isMultisite() ? add_site_option( $sKey, $sValue ) : add_option( $sKey, $sValue );
198
- }
199
 
200
- /**
201
- * @param string $sKey
202
- * @param $sValue
203
- * @return mixed
204
- */
205
- public function updateOption( $sKey, $sValue ) {
206
- return $this->isMultisite() ? update_site_option( $sKey, $sValue ) : update_option( $sKey, $sValue );
207
- }
208
 
209
- /**
210
- * @param string $sKey
211
- * @param mixed $mDefault
212
- * @return mixed
213
- */
214
- public function getOption( $sKey, $mDefault = false ) {
215
- return $this->isMultisite() ? get_site_option( $sKey, $mDefault ) : get_option( $sKey, $mDefault );
216
- }
217
 
218
- /**
219
- * @param string $sKey
220
- * @return mixed
221
- */
222
- public function deleteOption( $sKey ) {
223
- return $this->isMultisite() ? delete_site_option( $sKey ) : delete_option( $sKey );
224
- }
 
 
 
 
 
 
 
 
 
 
 
225
 
226
- /**
227
- */
228
- public function getCurrentWpAdminPage() {
229
- $sScript = isset( $_SERVER['SCRIPT_NAME'] )? $_SERVER['SCRIPT_NAME'] : $_SERVER['PHP_SELF'];
230
- if ( is_admin() && !empty( $sScript ) && basename( $sScript ) == 'admin.php' && isset( $_GET['page'] ) ) {
231
- $sCurrentPage = $_GET['page'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  }
233
- return empty($sCurrentPage)? '' : $sCurrentPage;
234
- }
235
 
236
- }
 
 
 
 
 
 
 
 
 
237
  endif;
238
 
239
- if ( !class_exists('ICWP_WpFunctions_WPSF') ):
240
 
241
- class ICWP_WpFunctions_WPSF extends ICWP_WpFunctions_V4 {
242
  /**
243
- * @return ICWP_WpFunctions_WPSF
244
  */
245
  public static function GetInstance() {
246
  if ( is_null( self::$oInstance ) ) {
2
  /**
3
  * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
+ *
6
  * Version: 2013-08-14_A
7
  *
8
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
  */
19
 
20
+ require_once( dirname(__FILE__).'/icwp-data-processor.php' );
21
+
22
+ if ( !class_exists('ICWP_WpFunctions_V5') ):
23
 
24
+ class ICWP_WpFunctions_V5 {
25
 
26
+ /**
27
+ * @var ICWP_WpFunctions_V5
28
+ */
29
+ protected static $oInstance = NULL;
30
 
31
+ /**
32
+ * @return ICWP_WpFunctions_V5
33
+ */
34
+ public static function GetInstance() {
35
+ if ( is_null( self::$oInstance ) ) {
36
+ self::$oInstance = new self();
37
+ }
38
+ return self::$oInstance;
39
+ }
40
+
41
+ /**
42
+ * @var string
43
+ */
44
+ protected $sWpVersion;
45
+
46
+ /**
47
+ * @var boolean
48
+ */
49
+ protected $fIsMultisite;
50
+
51
+ public function __construct() {}
52
+
53
+ /**
54
+ * The full plugin file to be upgraded.
55
+ *
56
+ * @param string $sPluginFile
57
+ * @return boolean
58
+ */
59
+ public function doPluginUpgrade( $sPluginFile ) {
60
+
61
+ if ( !$this->getIsPluginUpdateAvailable( $sPluginFile )
62
+ || ( isset( $GLOBALS['pagenow'] ) && $GLOBALS['pagenow'] == 'update.php' ) ) {
63
+ return true;
64
+ }
65
+ $sUrl = $this->getPluginUpgradeLink( $sPluginFile );
66
+ wp_redirect( $sUrl );
67
+ exit();
68
  }
 
 
69
 
70
+ /**
71
+ * @param string $sPluginFile
72
+ * @return boolean|stdClass
73
+ */
74
+ public function getIsPluginUpdateAvailable( $sPluginFile ) {
75
+ $aUpdates = $this->getWordpressUpdates();
76
+ if ( empty( $aUpdates ) ) {
77
+ return false;
78
+ }
79
+ if ( isset( $aUpdates[ $sPluginFile ] ) ) {
80
+ return $aUpdates[ $sPluginFile ];
81
+ }
 
 
 
 
 
 
 
82
  return false;
83
  }
84
+
85
+ /**
86
+ * @param string $sCompareString
87
+ * @param string $sKey
88
+ * @return bool
89
+ */
90
+ public function getIsPluginActive( $sCompareString, $sKey = 'Name' ) {
91
+
92
+ $sPluginFile = $this->getIsPluginInstalled( $sCompareString, $sKey );
93
+ if ( !$sPluginFile ) {
94
+ return false;
95
+ }
96
+ return is_plugin_active( $sPluginFile ) ? $sPluginFile : false;
97
  }
 
 
98
 
99
+ /**
100
+ * @param string $sCompareString
101
+ * @param string $sKey
102
+ * @return bool|string
103
+ */
104
+ public function getIsPluginInstalled( $sCompareString, $sKey = 'Name' ) {
105
+ $aPlugins = $this->getPlugins();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
+ if ( empty( $aPlugins ) || !is_array( $aPlugins ) ) {
108
+ return false;
109
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
+ foreach( $aPlugins as $sBaseFileName => $aPluginData ) {
112
+ if ( isset( $aPluginData[$sKey] ) && $sCompareString == $aPluginData[$sKey] ) {
113
+ return $sBaseFileName;
114
+ }
115
+ }
116
+ return false;
117
+ }
118
 
119
+ /**
120
+ * @param string $sPluginFile
121
+ * @return string
122
+ */
123
+ public function getPluginActivateLink( $sPluginFile ) {
124
+ $sUrl = self_admin_url( 'plugins.php' ) ;
125
+ $aQueryArgs = array(
126
+ 'action' => 'activate',
127
+ 'plugin' => urlencode( $sPluginFile ),
128
+ '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $sPluginFile )
129
+ );
130
+ return add_query_arg( $aQueryArgs, $sUrl );
131
+ }
132
 
133
+ /**
134
+ * @param string $sPluginFile
135
+ * @return string
136
+ */
137
+ public function getPluginDeactivateLink( $sPluginFile ) {
138
+ $sUrl = self_admin_url( 'plugins.php' ) ;
139
+ $aQueryArgs = array(
140
+ 'action' => 'deactivate',
141
+ 'plugin' => urlencode( $sPluginFile ),
142
+ '_wpnonce' => wp_create_nonce( 'deactivate-plugin_' . $sPluginFile )
143
+ );
144
+ return add_query_arg( $aQueryArgs, $sUrl );
145
+ }
146
 
147
+ /**
148
+ * @param string $sPluginFile
149
+ * @return string
150
+ */
151
+ public function getPluginUpgradeLink( $sPluginFile ) {
152
+ $sUrl = self_admin_url( 'update.php' ) ;
153
+ $aQueryArgs = array(
154
+ 'action' => 'upgrade-plugin',
155
+ 'plugin' => urlencode( $sPluginFile ),
156
+ '_wpnonce' => wp_create_nonce( 'upgrade-plugin_' . $sPluginFile )
157
+ );
158
+ return add_query_arg( $aQueryArgs, $sUrl );
159
  }
 
 
160
 
161
+ /**
162
+ * @return array
163
+ */
164
+ public function getWordpressUpdates() {
165
+ $oCurrent = $this->getTransient( 'update_plugins' );
166
+ return ( is_object( $oCurrent ) && isset( $oCurrent->response ) ) ? $oCurrent->response : array();
167
+ }
 
168
 
169
+ /**
170
+ * @return array
171
+ */
172
+ public function getPlugins() {
173
+ return function_exists( 'get_plugins' ) ? get_plugins() : array();
174
+ }
 
 
175
 
176
+ /**
177
+ * @param string $sKey
178
+ * @return object
179
+ */
180
+ protected function getTransient( $sKey ) {
 
 
 
181
 
182
+ // TODO: Handle multisite
183
+
184
+ if ( version_compare( $this->getWordpressVersion(), '2.7.9', '<=' ) ) {
185
+ return get_option( $sKey );
186
+ }
187
+
188
+ if ( function_exists( 'get_site_transient' ) ) {
189
+ $mResult = get_site_transient( $sKey );
190
+ if ( empty( $mResult ) ) {
191
+ remove_all_filters( 'pre_site_transient_'.$sKey );
192
+ $mResult = get_site_transient( $sKey );
193
+ }
194
+ return $mResult;
195
+ }
196
+
197
+ if ( version_compare( $this->getWordpressVersion(), '2.9.9', '<=' ) ) {
198
+ return apply_filters( 'transient_'.$sKey, get_option( '_transient_'.$sKey ) );
199
+ }
200
 
201
+ return apply_filters( 'site_transient_'.$sKey, get_option( '_site_transient_'.$sKey ) );
202
+ }
203
+
204
+ /**
205
+ * @return string
206
+ */
207
+ public function getWordpressVersion() {
208
+ global $wp_version;
209
+
210
+ if ( empty( $this->sWpVersion ) ) {
211
+ $sVersionFile = ABSPATH.WPINC.'/version.php';
212
+ $sVersionContents = file_get_contents( $sVersionFile );
213
+
214
+ if ( preg_match( '/wp_version\s=\s\'([^(\'|")]+)\'/i', $sVersionContents, $aMatches ) ) {
215
+ $this->sWpVersion = $aMatches[1];
216
+ }
217
+ }
218
+ return empty( $this->sWpVersion )? $wp_version : $this->sWpVersion;
219
+ }
220
+
221
+ /**
222
+ * @param array $aQueryParams
223
+ */
224
+ public function redirectToLogin( $aQueryParams = array() ) {
225
+ $sLoginUrl = $this->getWpLoginUrl();
226
+ $this->doRedirect( $sLoginUrl, $aQueryParams );
227
+ }
228
+ /**
229
+ * @param $aQueryParams
230
+ */
231
+ public function redirectToAdmin( $aQueryParams = array() ) {
232
+ $this->doRedirect( is_multisite()? get_admin_url() : admin_url(), $aQueryParams );
233
+ }
234
+ /**
235
+ * @param $aQueryParams
236
+ */
237
+ public function redirectToHome( $aQueryParams = array() ) {
238
+ $this->doRedirect( home_url(), $aQueryParams );
239
+ }
240
+
241
+ /**
242
+ * @param $sUrl
243
+ * @param $aQueryParams
244
+ * @uses exit()
245
+ */
246
+ public function doRedirect( $sUrl, $aQueryParams = array() ) {
247
+ $sUrl = empty( $aQueryParams ) ? $sUrl : add_query_arg( $aQueryParams, $sUrl ) ;
248
+ wp_safe_redirect( $sUrl );
249
+ exit();
250
+ }
251
+
252
+ /**
253
+ * @return string
254
+ */
255
+ public function getCurrentPage() {
256
+ global $pagenow;
257
+ return $pagenow;
258
+ }
259
+
260
+ /**
261
+ * @return string
262
+ */
263
+ public function getUrl_CurrentAdminPage() {
264
+
265
+ $sPage = $this->getCurrentPage();
266
+ $sUrl = self_admin_url( $sPage );
267
+
268
+ //special case for plugin admin pages.
269
+ if ( $sPage == 'admin.php' ) {
270
+ $sSubPage = $this->loadDataProcessor()->FetchGet( 'page' );
271
+ if ( !empty( $sSubPage ) ) {
272
+ $aQueryArgs = array(
273
+ 'page' => $sSubPage,
274
+ );
275
+ $sUrl = add_query_arg( $aQueryArgs, $sUrl );
276
+ }
277
+ }
278
+ return $sUrl;
279
+ }
280
+
281
+ /**
282
+ * @param string
283
+ * @return string
284
+ */
285
+ public function getIsCurrentPage( $sPage ) {
286
+ return $sPage == $this->getCurrentPage();
287
+ }
288
+
289
+ /**
290
+ * @param string
291
+ * @return string
292
+ */
293
+ public function getIsPage_Updates() {
294
+ return $this->getIsCurrentPage( 'update.php' );
295
+ }
296
+
297
+ /**
298
+ * @return bool
299
+ */
300
+ public function getIsLoginRequest() {
301
+ $oDp = $this->loadDataProcessor();
302
+ return
303
+ $oDp->GetIsRequestPost()
304
+ && $this->getIsCurrentPage( 'wp-login.php' )
305
+ && !is_null( $oDp->FetchPost( 'log' ) )
306
+ && !is_null( $oDp->FetchPost( 'pwd' ) );
307
+ }
308
+
309
+ /**
310
+ * @return bool
311
+ */
312
+ public function getIsXmlrpc() {
313
+ // XML-RPC Compatibility
314
+ return ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST );
315
+ }
316
+
317
+ /**
318
+ * @return string
319
+ */
320
+ public function getSiteName() {
321
+ return function_exists( 'get_bloginfo' )? get_bloginfo('name') : 'WordPress Site';
322
+ }
323
+ /**
324
+ * @return string
325
+ */
326
+ public function getSiteAdminEmail() {
327
+ return function_exists( 'get_bloginfo' )? get_bloginfo('admin_email') : '';
328
+ }
329
+
330
+ /**
331
+ * @return string
332
+ */
333
+ public function getCookieDomain() {
334
+ return defined( 'COOKIE_DOMAIN' ) ? COOKIE_DOMAIN : false;
335
+ }
336
+
337
+ /**
338
+ * @return string
339
+ */
340
+ public function getCookiePath() {
341
+ return defined( 'COOKIEPATH' ) ? COOKIEPATH : '/';
342
+ }
343
+
344
+ /**
345
+ * @return boolean
346
+ */
347
+ public function getIsAjax() {
348
+ return defined( 'DOING_AJAX' ) && DOING_AJAX;
349
+ }
350
+
351
+ /**
352
+ * @return boolean
353
+ */
354
+ public function getIsCron() {
355
+ return defined( 'DOING_CRON' ) && DOING_CRON;
356
+ }
357
+
358
+ /**
359
+ * @param int $nId
360
+ * @return WP_User|null
361
+ */
362
+ public function getUserById( $nId ) {
363
+ if ( version_compare( $this->getWordpressVersion(), '2.8.0', '<' ) || !function_exists( 'get_user_by' ) ) {
364
+ return null;
365
+ }
366
+ return get_user_by( 'id', $nId );
367
+ }
368
+
369
+ /**
370
+ * @param array $aLoginUrlParams
371
+ */
372
+ public function forceUserRelogin( $aLoginUrlParams = array() ) {
373
+ $this->logoutUser();
374
+ $this->redirectToLogin( $aLoginUrlParams );
375
+ }
376
+
377
+ /**
378
+ * @param string $sRedirectUrl
379
+ */
380
+ public function logoutUser( $sRedirectUrl = '' ) {
381
+ empty( $sRedirectUrl ) ? wp_logout() : wp_logout_url( $sRedirectUrl );
382
+ }
383
+
384
+ /**
385
+ * @return bool
386
+ */
387
+ public function isMultisite() {
388
+ if ( !isset( $this->fIsMultisite ) ) {
389
+ $this->fIsMultisite = function_exists( 'is_multisite' ) && is_multisite();
390
+ }
391
+ return $this->fIsMultisite;
392
+ }
393
+
394
+ /**
395
+ * @param string $sKey
396
+ * @param string $sValue
397
+ * @return bool
398
+ */
399
+ public function addOption( $sKey, $sValue ) {
400
+ return $this->isMultisite() ? add_site_option( $sKey, $sValue ) : add_option( $sKey, $sValue );
401
+ }
402
+
403
+ /**
404
+ * @param string $sKey
405
+ * @param $sValue
406
+ * @return boolean
407
+ */
408
+ public function updateOption( $sKey, $sValue ) {
409
+ return $this->isMultisite() ? update_site_option( $sKey, $sValue ) : update_option( $sKey, $sValue );
410
+ }
411
+
412
+ /**
413
+ * @param string $sKey
414
+ * @param mixed $mDefault
415
+ * @return mixed
416
+ */
417
+ public function getOption( $sKey, $mDefault = false ) {
418
+ return $this->isMultisite() ? get_site_option( $sKey, $mDefault ) : get_option( $sKey, $mDefault );
419
+ }
420
+
421
+ /**
422
+ * @param string $sKey
423
+ * @return mixed
424
+ */
425
+ public function deleteOption( $sKey ) {
426
+ return $this->isMultisite() ? delete_site_option( $sKey ) : delete_option( $sKey );
427
+ }
428
+
429
+ /**
430
+ * @return string
431
+ */
432
+ public function getCurrentWpAdminPage() {
433
+
434
+ $oDp = $this->loadDataProcessor();
435
+ $sScript = $oDp->FetchServer( 'SCRIPT_NAME' );
436
+ if ( empty( $sScript ) ) {
437
+ $sScript = $oDp->FetchServer( 'PHP_SELF' );
438
+ }
439
+ if ( is_admin() && !empty( $sScript ) && basename( $sScript ) == 'admin.php' ) {
440
+ $sCurrentPage = $oDp->FetchGet( 'page' );
441
+ }
442
+ return empty( $sCurrentPage ) ? '' : $sCurrentPage;
443
+ }
444
+
445
+ /**
446
+ * @return null|WP_User
447
+ */
448
+ public function getCurrentWpUser() {
449
+ if ( is_user_logged_in() ) {
450
+ $oUser = wp_get_current_user();
451
+ if ( is_object( $oUser ) && $oUser instanceof WP_User ) {
452
+ return $oUser;
453
+ }
454
+ }
455
+ return null;
456
+ }
457
+
458
+ /**
459
+ * @param $sUsername
460
+ */
461
+ public function setUserLoggedIn( $sUsername ) {
462
+ $oUser = version_compare( $this->getWordpressVersion(), '2.8.0', '<' )? get_userdatabylogin( $sUsername ) : get_user_by( 'login', $sUsername );
463
+
464
+ wp_clear_auth_cookie();
465
+ wp_set_current_user ( $oUser->ID, $oUser->user_login );
466
+ wp_set_auth_cookie ( $oUser->ID, true );
467
+ do_action( 'wp_login', $oUser->user_login, $oUser );
468
+ }
469
+
470
+ /**
471
+ * @return string
472
+ */
473
+ protected function getWpLoginUrl() {
474
+ return site_url() . '/wp-login.php';
475
+ }
476
+
477
+ /**
478
+ * @param string $sKey should be already prefixed
479
+ * @param string $nId
480
+ * @return bool|string
481
+ */
482
+ public function getUserMeta( $sKey, $nId = null ) {
483
+ $nUserId = $nId;
484
+ if ( empty( $nUserId ) ) {
485
+ $oCurrentUser = $this->getCurrentWpUser();
486
+ if ( is_null( $oCurrentUser ) ) {
487
+ return false;
488
+ }
489
+ $nUserId = $oCurrentUser->ID;
490
+ }
491
+
492
+ $sCurrentMetaValue = get_user_meta( $nUserId, $sKey, true );
493
+ // A guard whereby if we can't ever get a value for this meta, it means we can never set it.
494
+ if ( empty( $sCurrentMetaValue ) ) {
495
+ //the value has never been set, or it's been installed for the first time.
496
+ $this->updateUserMeta( $sKey, 'temp', $nUserId );
497
+ return '';
498
+ }
499
+ return $sCurrentMetaValue;
500
+ }
501
+
502
+ /**
503
+ * Updates the user meta data for the current (or supplied user ID)
504
+ *
505
+ * @param string $sKey
506
+ * @param mixed $mValue
507
+ * @param integer $nId -user ID
508
+ * @return boolean
509
+ */
510
+ public function updateUserMeta( $sKey, $mValue, $nId = null ) {
511
+ $nUserId = $nId;
512
+ if ( empty( $nUserId ) ) {
513
+ $oCurrentUser = $this->getCurrentWpUser();
514
+ if ( is_null( $oCurrentUser ) ) {
515
+ return false;
516
+ }
517
+ $nUserId = $oCurrentUser->ID;
518
+ }
519
+ return update_user_meta( $nUserId, $sKey, $mValue );
520
  }
 
 
521
 
522
+ /**
523
+ * @return ICWP_WPSF_DataProcessor
524
+ */
525
+ public function loadDataProcessor() {
526
+ if ( !class_exists('ICWP_WPSF_DataProcessor') ) {
527
+ require_once( dirname(__FILE__).'/icwp-data-processor.php' );
528
+ }
529
+ return ICWP_WPSF_DataProcessor::GetInstance();
530
+ }
531
+ }
532
  endif;
533
 
534
+ if ( !class_exists('ICWP_WPSF_WpFunctions') ):
535
 
536
+ class ICWP_WPSF_WpFunctions extends ICWP_WpFunctions_V5 {
537
  /**
538
+ * @return ICWP_WPSF_WpFunctions
539
  */
540
  public static function GetInstance() {
541
  if ( is_null( self::$oInstance ) ) {
src/lib/yaml/Spyc.php ADDED
@@ -0,0 +1,1147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Spyc -- A Simple PHP YAML Class
4
+ * @version 0.5.1
5
+ * @author Vlad Andersen <vlad.andersen@gmail.com>
6
+ * @author Chris Wanstrath <chris@ozmm.org>
7
+ * @link https://github.com/mustangostang/spyc/
8
+ * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen
9
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
10
+ * @package Spyc
11
+ */
12
+
13
+ if (!function_exists('spyc_load')) {
14
+ /**
15
+ * Parses YAML to array.
16
+ * @param string $string YAML string.
17
+ * @return array
18
+ */
19
+ function spyc_load ($string) {
20
+ return Spyc::YAMLLoadString($string);
21
+ }
22
+ }
23
+
24
+ if (!function_exists('spyc_load_file')) {
25
+ /**
26
+ * Parses YAML to array.
27
+ * @param string $file Path to YAML file.
28
+ * @return array
29
+ */
30
+ function spyc_load_file ($file) {
31
+ return Spyc::YAMLLoad($file);
32
+ }
33
+ }
34
+
35
+ if (!function_exists('spyc_dump')) {
36
+ /**
37
+ * Dumps array to YAML.
38
+ * @param array $data Array.
39
+ * @return string
40
+ */
41
+ function spyc_dump ($data) {
42
+ return Spyc::YAMLDump($data, false, false, true);
43
+ }
44
+ }
45
+
46
+ /**
47
+ * The Simple PHP YAML Class.
48
+ *
49
+ * This class can be used to read a YAML file and convert its contents
50
+ * into a PHP array. It currently supports a very limited subsection of
51
+ * the YAML spec.
52
+ *
53
+ * Usage:
54
+ * <code>
55
+ * $Spyc = new Spyc;
56
+ * $array = $Spyc->load($file);
57
+ * </code>
58
+ * or:
59
+ * <code>
60
+ * $array = Spyc::YAMLLoad($file);
61
+ * </code>
62
+ * or:
63
+ * <code>
64
+ * $array = spyc_load_file($file);
65
+ * </code>
66
+ * @package Spyc
67
+ */
68
+ class Spyc {
69
+
70
+ // SETTINGS
71
+
72
+ const REMPTY = "\0\0\0\0\0";
73
+
74
+ /**
75
+ * Setting this to true will force YAMLDump to enclose any string value in
76
+ * quotes. False by default.
77
+ *
78
+ * @var bool
79
+ */
80
+ public $setting_dump_force_quotes = false;
81
+
82
+ /**
83
+ * Setting this to true will forse YAMLLoad to use syck_load function when
84
+ * possible. False by default.
85
+ * @var bool
86
+ */
87
+ public $setting_use_syck_is_possible = false;
88
+
89
+
90
+
91
+ /**#@+
92
+ * @access private
93
+ * @var mixed
94
+ */
95
+ private $_dumpIndent;
96
+ private $_dumpWordWrap;
97
+ private $_containsGroupAnchor = false;
98
+ private $_containsGroupAlias = false;
99
+ private $path;
100
+ private $result;
101
+ private $LiteralPlaceHolder = '___YAML_Literal_Block___';
102
+ private $SavedGroups = array();
103
+ private $indent;
104
+ /**
105
+ * Path modifier that should be applied after adding current element.
106
+ * @var array
107
+ */
108
+ private $delayedPath = array();
109
+
110
+ /**#@+
111
+ * @access public
112
+ * @var mixed
113
+ */
114
+ public $_nodeId;
115
+
116
+ /**
117
+ * Load a valid YAML string to Spyc.
118
+ * @param string $input
119
+ * @return array
120
+ */
121
+ public function load ($input) {
122
+ return $this->__loadString($input);
123
+ }
124
+
125
+ /**
126
+ * Load a valid YAML file to Spyc.
127
+ * @param string $file
128
+ * @return array
129
+ */
130
+ public function loadFile ($file) {
131
+ return $this->__load($file);
132
+ }
133
+
134
+ /**
135
+ * Load YAML into a PHP array statically
136
+ *
137
+ * The load method, when supplied with a YAML stream (string or file),
138
+ * will do its best to convert YAML in a file into a PHP array. Pretty
139
+ * simple.
140
+ * Usage:
141
+ * <code>
142
+ * $array = Spyc::YAMLLoad('lucky.yaml');
143
+ * print_r($array);
144
+ * </code>
145
+ * @access public
146
+ * @return array
147
+ * @param string $input Path of YAML file or string containing YAML
148
+ */
149
+ public static function YAMLLoad($input) {
150
+ $Spyc = new Spyc;
151
+ return $Spyc->__load($input);
152
+ }
153
+
154
+ /**
155
+ * Load a string of YAML into a PHP array statically
156
+ *
157
+ * The load method, when supplied with a YAML string, will do its best
158
+ * to convert YAML in a string into a PHP array. Pretty simple.
159
+ *
160
+ * Note: use this function if you don't want files from the file system
161
+ * loaded and processed as YAML. This is of interest to people concerned
162
+ * about security whose input is from a string.
163
+ *
164
+ * Usage:
165
+ * <code>
166
+ * $array = Spyc::YAMLLoadString("---\n0: hello world\n");
167
+ * print_r($array);
168
+ * </code>
169
+ * @access public
170
+ * @return array
171
+ * @param string $input String containing YAML
172
+ */
173
+ public static function YAMLLoadString($input) {
174
+ $Spyc = new Spyc;
175
+ return $Spyc->__loadString($input);
176
+ }
177
+
178
+ /**
179
+ * Dump YAML from PHP array statically
180
+ *
181
+ * The dump method, when supplied with an array, will do its best
182
+ * to convert the array into friendly YAML. Pretty simple. Feel free to
183
+ * save the returned string as nothing.yaml and pass it around.
184
+ *
185
+ * Oh, and you can decide how big the indent is and what the wordwrap
186
+ * for folding is. Pretty cool -- just pass in 'false' for either if
187
+ * you want to use the default.
188
+ *
189
+ * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
190
+ * you can turn off wordwrap by passing in 0.
191
+ *
192
+ * @access public
193
+ * @return string
194
+ * @param array $array PHP array
195
+ * @param int $indent Pass in false to use the default, which is 2
196
+ * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
197
+ * @param int $no_opening_dashes Do not start YAML file with "---\n"
198
+ */
199
+ public static function YAMLDump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) {
200
+ $spyc = new Spyc;
201
+ return $spyc->dump($array, $indent, $wordwrap, $no_opening_dashes);
202
+ }
203
+
204
+
205
+ /**
206
+ * Dump PHP array to YAML
207
+ *
208
+ * The dump method, when supplied with an array, will do its best
209
+ * to convert the array into friendly YAML. Pretty simple. Feel free to
210
+ * save the returned string as tasteful.yaml and pass it around.
211
+ *
212
+ * Oh, and you can decide how big the indent is and what the wordwrap
213
+ * for folding is. Pretty cool -- just pass in 'false' for either if
214
+ * you want to use the default.
215
+ *
216
+ * Indent's default is 2 spaces, wordwrap's default is 40 characters. And
217
+ * you can turn off wordwrap by passing in 0.
218
+ *
219
+ * @access public
220
+ * @return string
221
+ * @param array $array PHP array
222
+ * @param int $indent Pass in false to use the default, which is 2
223
+ * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
224
+ */
225
+ public function dump($array,$indent = false,$wordwrap = false, $no_opening_dashes = false) {
226
+ // Dumps to some very clean YAML. We'll have to add some more features
227
+ // and options soon. And better support for folding.
228
+
229
+ // New features and options.
230
+ if ($indent === false or !is_numeric($indent)) {
231
+ $this->_dumpIndent = 2;
232
+ } else {
233
+ $this->_dumpIndent = $indent;
234
+ }
235
+
236
+ if ($wordwrap === false or !is_numeric($wordwrap)) {
237
+ $this->_dumpWordWrap = 40;
238
+ } else {
239
+ $this->_dumpWordWrap = $wordwrap;
240
+ }
241
+
242
+ // New YAML document
243
+ $string = "";
244
+ if (!$no_opening_dashes) $string = "---\n";
245
+
246
+ // Start at the base of the array and move through it.
247
+ if ($array) {
248
+ $array = (array)$array;
249
+ $previous_key = -1;
250
+ foreach ($array as $key => $value) {
251
+ if (!isset($first_key)) $first_key = $key;
252
+ $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array);
253
+ $previous_key = $key;
254
+ }
255
+ }
256
+ return $string;
257
+ }
258
+
259
+ /**
260
+ * Attempts to convert a key / value array item to YAML
261
+ * @access private
262
+ * @return string
263
+ * @param $key The name of the key
264
+ * @param $value The value of the item
265
+ * @param $indent The indent of the current node
266
+ */
267
+ private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) {
268
+ if (is_array($value)) {
269
+ if (empty ($value))
270
+ return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array);
271
+ // It has children. What to do?
272
+ // Make it the right kind of item
273
+ $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array);
274
+ // Add the indent
275
+ $indent += $this->_dumpIndent;
276
+ // Yamlize the array
277
+ $string .= $this->_yamlizeArray($value,$indent);
278
+ } elseif (!is_array($value)) {
279
+ // It doesn't have children. Yip.
280
+ $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array);
281
+ }
282
+ return $string;
283
+ }
284
+
285
+ /**
286
+ * Attempts to convert an array to YAML
287
+ * @access private
288
+ * @return string
289
+ * @param $array The array you want to convert
290
+ * @param $indent The indent of the current level
291
+ */
292
+ private function _yamlizeArray($array,$indent) {
293
+ if (is_array($array)) {
294
+ $string = '';
295
+ $previous_key = -1;
296
+ foreach ($array as $key => $value) {
297
+ if (!isset($first_key)) $first_key = $key;
298
+ $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array);
299
+ $previous_key = $key;
300
+ }
301
+ return $string;
302
+ } else {
303
+ return false;
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Returns YAML from a key and a value
309
+ * @access private
310
+ * @return string
311
+ * @param $key The name of the key
312
+ * @param $value The value of the item
313
+ * @param $indent The indent of the current node
314
+ */
315
+ private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) {
316
+ // do some folding here, for blocks
317
+ if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false ||
318
+ strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, ' ') !== false ||
319
+ strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 ||
320
+ substr ($value, -1, 1) == ':')
321
+ ) {
322
+ $value = $this->_doLiteralBlock($value,$indent);
323
+ } else {
324
+ $value = $this->_doFolding($value,$indent);
325
+ }
326
+
327
+ if ($value === array()) $value = '[ ]';
328
+ if ($value === "") $value = '""';
329
+ if (self::isTranslationWord($value)) {
330
+ $value = $this->_doLiteralBlock($value, $indent);
331
+ }
332
+ if (trim ($value) != $value)
333
+ $value = $this->_doLiteralBlock($value,$indent);
334
+
335
+ if (is_bool($value)) {
336
+ $value = $value ? "true" : "false";
337
+ }
338
+
339
+ if ($value === null) $value = 'null';
340
+ if ($value === "'" . self::REMPTY . "'") $value = null;
341
+
342
+ $spaces = str_repeat(' ',$indent);
343
+
344
+ //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) {
345
+ if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) {
346
+ // It's a sequence
347
+ $string = $spaces.'- '.$value."\n";
348
+ } else {
349
+ // if ($first_key===0) throw new Exception('Keys are all screwy. The first one was zero, now it\'s "'. $key .'"');
350
+ // It's mapped
351
+ if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; }
352
+ $string = rtrim ($spaces.$key.': '.$value)."\n";
353
+ }
354
+ return $string;
355
+ }
356
+
357
+ /**
358
+ * Creates a literal block for dumping
359
+ * @access private
360
+ * @return string
361
+ * @param $value
362
+ * @param $indent int The value of the indent
363
+ */
364
+ private function _doLiteralBlock($value,$indent) {
365
+ if ($value === "\n") return '\n';
366
+ if (strpos($value, "\n") === false && strpos($value, "'") === false) {
367
+ return sprintf ("'%s'", $value);
368
+ }
369
+ if (strpos($value, "\n") === false && strpos($value, '"') === false) {
370
+ return sprintf ('"%s"', $value);
371
+ }
372
+ $exploded = explode("\n",$value);
373
+ $newValue = '|';
374
+ $indent += $this->_dumpIndent;
375
+ $spaces = str_repeat(' ',$indent);
376
+ foreach ($exploded as $line) {
377
+ $newValue .= "\n" . $spaces . ($line);
378
+ }
379
+ return $newValue;
380
+ }
381
+
382
+ /**
383
+ * Folds a string of text, if necessary
384
+ * @access private
385
+ * @return string
386
+ * @param $value The string you wish to fold
387
+ */
388
+ private function _doFolding($value,$indent) {
389
+ // Don't do anything if wordwrap is set to 0
390
+
391
+ if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) {
392
+ $indent += $this->_dumpIndent;
393
+ $indent = str_repeat(' ',$indent);
394
+ $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
395
+ $value = ">\n".$indent.$wrapped;
396
+ } else {
397
+ if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY)
398
+ $value = '"' . $value . '"';
399
+ if (is_numeric($value) && is_string($value))
400
+ $value = '"' . $value . '"';
401
+ }
402
+
403
+
404
+ return $value;
405
+ }
406
+
407
+ private function isTrueWord($value) {
408
+ $words = self::getTranslations(array('true', 'on', 'yes', 'y'));
409
+ return in_array($value, $words, true);
410
+ }
411
+
412
+ private function isFalseWord($value) {
413
+ $words = self::getTranslations(array('false', 'off', 'no', 'n'));
414
+ return in_array($value, $words, true);
415
+ }
416
+
417
+ private function isNullWord($value) {
418
+ $words = self::getTranslations(array('null', '~'));
419
+ return in_array($value, $words, true);
420
+ }
421
+
422
+ private function isTranslationWord($value) {
423
+ return (
424
+ self::isTrueWord($value) ||
425
+ self::isFalseWord($value) ||
426
+ self::isNullWord($value)
427
+ );
428
+ }
429
+
430
+ /**
431
+ * Coerce a string into a native type
432
+ * Reference: http://yaml.org/type/bool.html
433
+ * TODO: Use only words from the YAML spec.
434
+ * @access private
435
+ * @param $value The value to coerce
436
+ */
437
+ private function coerceValue(&$value) {
438
+ if (self::isTrueWord($value)) {
439
+ $value = true;
440
+ } else if (self::isFalseWord($value)) {
441
+ $value = false;
442
+ } else if (self::isNullWord($value)) {
443
+ $value = null;
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Given a set of words, perform the appropriate translations on them to
449
+ * match the YAML 1.1 specification for type coercing.
450
+ * @param $words The words to translate
451
+ * @access private
452
+ */
453
+ private static function getTranslations(array $words) {
454
+ $result = array();
455
+ foreach ($words as $i) {
456
+ $result = array_merge($result, array(ucfirst($i), strtoupper($i), strtolower($i)));
457
+ }
458
+ return $result;
459
+ }
460
+
461
+ // LOADING FUNCTIONS
462
+
463
+ private function __load($input) {
464
+ $Source = $this->loadFromSource($input);
465
+ return $this->loadWithSource($Source);
466
+ }
467
+
468
+ private function __loadString($input) {
469
+ $Source = $this->loadFromString($input);
470
+ return $this->loadWithSource($Source);
471
+ }
472
+
473
+ private function loadWithSource($Source) {
474
+ if (empty ($Source)) return array();
475
+ if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) {
476
+ $array = syck_load (implode ("\n", $Source));
477
+ return is_array($array) ? $array : array();
478
+ }
479
+
480
+ $this->path = array();
481
+ $this->result = array();
482
+
483
+ $cnt = count($Source);
484
+ for ($i = 0; $i < $cnt; $i++) {
485
+ $line = $Source[$i];
486
+
487
+ $this->indent = strlen($line) - strlen(ltrim($line));
488
+ $tempPath = $this->getParentPathByIndent($this->indent);
489
+ $line = self::stripIndent($line, $this->indent);
490
+ if (self::isComment($line)) continue;
491
+ if (self::isEmpty($line)) continue;
492
+ $this->path = $tempPath;
493
+
494
+ $literalBlockStyle = self::startsLiteralBlock($line);
495
+ if ($literalBlockStyle) {
496
+ $line = rtrim ($line, $literalBlockStyle . " \n");
497
+ $literalBlock = '';
498
+ $line .= ' '.$this->LiteralPlaceHolder;
499
+ $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1]));
500
+ while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
501
+ $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent);
502
+ }
503
+ $i--;
504
+ }
505
+
506
+ // Strip out comments
507
+ if (strpos ($line, '#')) {
508
+ $line = preg_replace('/\s*#([^"\']+)$/','',$line);
509
+ }
510
+
511
+ while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
512
+ $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
513
+ }
514
+ $i--;
515
+
516
+ $lineArray = $this->_parseLine($line);
517
+
518
+ if ($literalBlockStyle)
519
+ $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
520
+
521
+ $this->addArray($lineArray, $this->indent);
522
+
523
+ foreach ($this->delayedPath as $indent => $delayedPath)
524
+ $this->path[$indent] = $delayedPath;
525
+
526
+ $this->delayedPath = array();
527
+
528
+ }
529
+ return $this->result;
530
+ }
531
+
532
+ private function loadFromSource ($input) {
533
+ if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
534
+ $input = file_get_contents($input);
535
+
536
+ return $this->loadFromString($input);
537
+ }
538
+
539
+ private function loadFromString ($input) {
540
+ $lines = explode("\n",$input);
541
+ foreach ($lines as $k => $_) {
542
+ $lines[$k] = rtrim ($_, "\r");
543
+ }
544
+ return $lines;
545
+ }
546
+
547
+ /**
548
+ * Parses YAML code and returns an array for a node
549
+ * @access private
550
+ * @return array
551
+ * @param string $line A line from the YAML file
552
+ */
553
+ private function _parseLine($line) {
554
+ if (!$line) return array();
555
+ $line = trim($line);
556
+ if (!$line) return array();
557
+
558
+ $array = array();
559
+
560
+ $group = $this->nodeContainsGroup($line);
561
+ if ($group) {
562
+ $this->addGroup($line, $group);
563
+ $line = $this->stripGroup ($line, $group);
564
+ }
565
+
566
+ if ($this->startsMappedSequence($line))
567
+ return $this->returnMappedSequence($line);
568
+
569
+ if ($this->startsMappedValue($line))
570
+ return $this->returnMappedValue($line);
571
+
572
+ if ($this->isArrayElement($line))
573
+ return $this->returnArrayElement($line);
574
+
575
+ if ($this->isPlainArray($line))
576
+ return $this->returnPlainArray($line);
577
+
578
+
579
+ return $this->returnKeyValuePair($line);
580
+
581
+ }
582
+
583
+ /**
584
+ * Finds the type of the passed value, returns the value as the new type.
585
+ * @access private
586
+ * @param string $value
587
+ * @return mixed
588
+ */
589
+ private function _toType($value) {
590
+ if ($value === '') return "";
591
+ $first_character = $value[0];
592
+ $last_character = substr($value, -1, 1);
593
+
594
+ $is_quoted = false;
595
+ do {
596
+ if (!$value) break;
597
+ if ($first_character != '"' && $first_character != "'") break;
598
+ if ($last_character != '"' && $last_character != "'") break;
599
+ $is_quoted = true;
600
+ } while (0);
601
+
602
+ if ($is_quoted) {
603
+ $value = str_replace('\n', "\n", $value);
604
+ return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\''));
605
+ }
606
+
607
+ if (strpos($value, ' #') !== false && !$is_quoted)
608
+ $value = preg_replace('/\s+#(.+)$/','',$value);
609
+
610
+ if ($first_character == '[' && $last_character == ']') {
611
+ // Take out strings sequences and mappings
612
+ $innerValue = trim(substr ($value, 1, -1));
613
+ if ($innerValue === '') return array();
614
+ $explode = $this->_inlineEscape($innerValue);
615
+ // Propagate value array
616
+ $value = array();
617
+ foreach ($explode as $v) {
618
+ $value[] = $this->_toType($v);
619
+ }
620
+ return $value;
621
+ }
622
+
623
+ if (strpos($value,': ')!==false && $first_character != '{') {
624
+ $array = explode(': ',$value);
625
+ $key = trim($array[0]);
626
+ array_shift($array);
627
+ $value = trim(implode(': ',$array));
628
+ $value = $this->_toType($value);
629
+ return array($key => $value);
630
+ }
631
+
632
+ if ($first_character == '{' && $last_character == '}') {
633
+ $innerValue = trim(substr ($value, 1, -1));
634
+ if ($innerValue === '') return array();
635
+ // Inline Mapping
636
+ // Take out strings sequences and mappings
637
+ $explode = $this->_inlineEscape($innerValue);
638
+ // Propagate value array
639
+ $array = array();
640
+ foreach ($explode as $v) {
641
+ $SubArr = $this->_toType($v);
642
+ if (empty($SubArr)) continue;
643
+ if (is_array ($SubArr)) {
644
+ $array[key($SubArr)] = $SubArr[key($SubArr)]; continue;
645
+ }
646
+ $array[] = $SubArr;
647
+ }
648
+ return $array;
649
+ }
650
+
651
+ if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') {
652
+ return null;
653
+ }
654
+
655
+ if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){
656
+ $intvalue = (int)$value;
657
+ if ($intvalue != PHP_INT_MAX)
658
+ $value = $intvalue;
659
+ return $value;
660
+ }
661
+
662
+ if (is_numeric($value) && preg_match('/^0[xX][0-9a-fA-F]+$/', $value)) {
663
+ // Hexadecimal value.
664
+ return hexdec($value);
665
+ }
666
+
667
+ $this->coerceValue($value);
668
+
669
+ if (is_numeric($value)) {
670
+ if ($value === '0') return 0;
671
+ if (rtrim ($value, 0) === $value)
672
+ $value = (float)$value;
673
+ return $value;
674
+ }
675
+
676
+ return $value;
677
+ }
678
+
679
+ /**
680
+ * Used in inlines to check for more inlines or quoted strings
681
+ * @access private
682
+ * @return array
683
+ */
684
+ private function _inlineEscape($inline) {
685
+ // There's gotta be a cleaner way to do this...
686
+ // While pure sequences seem to be nesting just fine,
687
+ // pure mappings and mappings with sequences inside can't go very
688
+ // deep. This needs to be fixed.
689
+
690
+ $seqs = array();
691
+ $maps = array();
692
+ $saved_strings = array();
693
+ $saved_empties = array();
694
+
695
+ // Check for empty strings
696
+ $regex = '/("")|(\'\')/';
697
+ if (preg_match_all($regex,$inline,$strings)) {
698
+ $saved_empties = $strings[0];
699
+ $inline = preg_replace($regex,'YAMLEmpty',$inline);
700
+ }
701
+ unset($regex);
702
+
703
+ // Check for strings
704
+ $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
705
+ if (preg_match_all($regex,$inline,$strings)) {
706
+ $saved_strings = $strings[0];
707
+ $inline = preg_replace($regex,'YAMLString',$inline);
708
+ }
709
+ unset($regex);
710
+
711
+ // echo $inline;
712
+
713
+ $i = 0;
714
+ do {
715
+
716
+ // Check for sequences
717
+ while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) {
718
+ $seqs[] = $matchseqs[0];
719
+ $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
720
+ }
721
+
722
+ // Check for mappings
723
+ while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) {
724
+ $maps[] = $matchmaps[0];
725
+ $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
726
+ }
727
+
728
+ if ($i++ >= 10) break;
729
+
730
+ } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
731
+
732
+ $explode = explode(',',$inline);
733
+ $explode = array_map('trim', $explode);
734
+ $stringi = 0; $i = 0;
735
+
736
+ while (1) {
737
+
738
+ // Re-add the sequences
739
+ if (!empty($seqs)) {
740
+ foreach ($explode as $key => $value) {
741
+ if (strpos($value,'YAMLSeq') !== false) {
742
+ foreach ($seqs as $seqk => $seq) {
743
+ $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value);
744
+ $value = $explode[$key];
745
+ }
746
+ }
747
+ }
748
+ }
749
+
750
+ // Re-add the mappings
751
+ if (!empty($maps)) {
752
+ foreach ($explode as $key => $value) {
753
+ if (strpos($value,'YAMLMap') !== false) {
754
+ foreach ($maps as $mapk => $map) {
755
+ $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value);
756
+ $value = $explode[$key];
757
+ }
758
+ }
759
+ }
760
+ }
761
+
762
+
763
+ // Re-add the strings
764
+ if (!empty($saved_strings)) {
765
+ foreach ($explode as $key => $value) {
766
+ while (strpos($value,'YAMLString') !== false) {
767
+ $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1);
768
+ unset($saved_strings[$stringi]);
769
+ ++$stringi;
770
+ $value = $explode[$key];
771
+ }
772
+ }
773
+ }
774
+
775
+
776
+ // Re-add the empties
777
+ if (!empty($saved_empties)) {
778
+ foreach ($explode as $key => $value) {
779
+ while (strpos($value,'YAMLEmpty') !== false) {
780
+ $explode[$key] = preg_replace('/YAMLEmpty/', '', $value, 1);
781
+ $value = $explode[$key];
782
+ }
783
+ }
784
+ }
785
+
786
+ $finished = true;
787
+ foreach ($explode as $key => $value) {
788
+ if (strpos($value,'YAMLSeq') !== false) {
789
+ $finished = false; break;
790
+ }
791
+ if (strpos($value,'YAMLMap') !== false) {
792
+ $finished = false; break;
793
+ }
794
+ if (strpos($value,'YAMLString') !== false) {
795
+ $finished = false; break;
796
+ }
797
+ if (strpos($value,'YAMLEmpty') !== false) {
798
+ $finished = false; break;
799
+ }
800
+ }
801
+ if ($finished) break;
802
+
803
+ $i++;
804
+ if ($i > 10)
805
+ break; // Prevent infinite loops.
806
+ }
807
+
808
+
809
+ return $explode;
810
+ }
811
+
812
+ private function literalBlockContinues ($line, $lineIndent) {
813
+ if (!trim($line)) return true;
814
+ if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true;
815
+ return false;
816
+ }
817
+
818
+ private function referenceContentsByAlias ($alias) {
819
+ do {
820
+ if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; }
821
+ $groupPath = $this->SavedGroups[$alias];
822
+ $value = $this->result;
823
+ foreach ($groupPath as $k) {
824
+ $value = $value[$k];
825
+ }
826
+ } while (false);
827
+ return $value;
828
+ }
829
+
830
+ private function addArrayInline ($array, $indent) {
831
+ $CommonGroupPath = $this->path;
832
+ if (empty ($array)) return false;
833
+
834
+ foreach ($array as $k => $_) {
835
+ $this->addArray(array($k => $_), $indent);
836
+ $this->path = $CommonGroupPath;
837
+ }
838
+ return true;
839
+ }
840
+
841
+ private function addArray ($incoming_data, $incoming_indent) {
842
+
843
+ // print_r ($incoming_data);
844
+
845
+ if (count ($incoming_data) > 1)
846
+ return $this->addArrayInline ($incoming_data, $incoming_indent);
847
+
848
+ $key = key ($incoming_data);
849
+ $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
850
+ if ($key === '__!YAMLZero') $key = '0';
851
+
852
+ if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
853
+ if ($key || $key === '' || $key === '0') {
854
+ $this->result[$key] = $value;
855
+ } else {
856
+ $this->result[] = $value; end ($this->result); $key = key ($this->result);
857
+ }
858
+ $this->path[$incoming_indent] = $key;
859
+ return;
860
+ }
861
+
862
+
863
+
864
+ $history = array();
865
+ // Unfolding inner array tree.
866
+ $history[] = $_arr = $this->result;
867
+ foreach ($this->path as $k) {
868
+ $history[] = $_arr = $_arr[$k];
869
+ }
870
+
871
+ if ($this->_containsGroupAlias) {
872
+ $value = $this->referenceContentsByAlias($this->_containsGroupAlias);
873
+ $this->_containsGroupAlias = false;
874
+ }
875
+
876
+
877
+ // Adding string or numeric key to the innermost level or $this->arr.
878
+ if (is_string($key) && $key == '<<') {
879
+ if (!is_array ($_arr)) { $_arr = array (); }
880
+
881
+ $_arr = array_merge ($_arr, $value);
882
+ } else if ($key || $key === '' || $key === '0') {
883
+ if (!is_array ($_arr))
884
+ $_arr = array ($key=>$value);
885
+ else
886
+ $_arr[$key] = $value;
887
+ } else {
888
+ if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
889
+ else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
890
+ }
891
+
892
+ $reverse_path = array_reverse($this->path);
893
+ $reverse_history = array_reverse ($history);
894
+ $reverse_history[0] = $_arr;
895
+ $cnt = count($reverse_history) - 1;
896
+ for ($i = 0; $i < $cnt; $i++) {
897
+ $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i];
898
+ }
899
+ $this->result = $reverse_history[$cnt];
900
+
901
+ $this->path[$incoming_indent] = $key;
902
+
903
+ if ($this->_containsGroupAnchor) {
904
+ $this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
905
+ if (is_array ($value)) {
906
+ $k = key ($value);
907
+ if (!is_int ($k)) {
908
+ $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
909
+ }
910
+ }
911
+ $this->_containsGroupAnchor = false;
912
+ }
913
+
914
+ }
915
+
916
+ private static function startsLiteralBlock ($line) {
917
+ $lastChar = substr (trim($line), -1);
918
+ if ($lastChar != '>' && $lastChar != '|') return false;
919
+ if ($lastChar == '|') return $lastChar;
920
+ // HTML tags should not be counted as literal blocks.
921
+ if (preg_match ('#<.*?>$#', $line)) return false;
922
+ return $lastChar;
923
+ }
924
+
925
+ private static function greedilyNeedNextLine($line) {
926
+ $line = trim ($line);
927
+ if (!strlen($line)) return false;
928
+ if (substr ($line, -1, 1) == ']') return false;
929
+ if ($line[0] == '[') return true;
930
+ if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true;
931
+ return false;
932
+ }
933
+
934
+ private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) {
935
+ $line = self::stripIndent($line, $indent);
936
+ if ($literalBlockStyle !== '|') {
937
+ $line = self::stripIndent($line);
938
+ }
939
+ $line = rtrim ($line, "\r\n\t ") . "\n";
940
+ if ($literalBlockStyle == '|') {
941
+ return $literalBlock . $line;
942
+ }
943
+ if (strlen($line) == 0)
944
+ return rtrim($literalBlock, ' ') . "\n";
945
+ if ($line == "\n" && $literalBlockStyle == '>') {
946
+ return rtrim ($literalBlock, " \t") . "\n";
947
+ }
948
+ if ($line != "\n")
949
+ $line = trim ($line, "\r\n ") . " ";
950
+ return $literalBlock . $line;
951
+ }
952
+
953
+ function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
954
+ foreach ($lineArray as $k => $_) {
955
+ if (is_array($_))
956
+ $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock);
957
+ else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
958
+ $lineArray[$k] = rtrim ($literalBlock, " \r\n");
959
+ }
960
+ return $lineArray;
961
+ }
962
+
963
+ private static function stripIndent ($line, $indent = -1) {
964
+ if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line));
965
+ return substr ($line, $indent);
966
+ }
967
+
968
+ private function getParentPathByIndent ($indent) {
969
+ if ($indent == 0) return array();
970
+ $linePath = $this->path;
971
+ do {
972
+ end($linePath); $lastIndentInParentPath = key($linePath);
973
+ if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
974
+ } while ($indent <= $lastIndentInParentPath);
975
+ return $linePath;
976
+ }
977
+
978
+
979
+ private function clearBiggerPathValues ($indent) {
980
+
981
+
982
+ if ($indent == 0) $this->path = array();
983
+ if (empty ($this->path)) return true;
984
+
985
+ foreach ($this->path as $k => $_) {
986
+ if ($k > $indent) unset ($this->path[$k]);
987
+ }
988
+
989
+ return true;
990
+ }
991
+
992
+
993
+ private static function isComment ($line) {
994
+ if (!$line) return false;
995
+ if ($line[0] == '#') return true;
996
+ if (trim($line, " \r\n\t") == '---') return true;
997
+ return false;
998
+ }
999
+
1000
+ private static function isEmpty ($line) {
1001
+ return (trim ($line) === '');
1002
+ }
1003
+
1004
+
1005
+ private function isArrayElement ($line) {
1006
+ if (!$line || !is_scalar($line)) return false;
1007
+ if (substr($line, 0, 2) != '- ') return false;
1008
+ if (strlen ($line) > 3)
1009
+ if (substr($line,0,3) == '---') return false;
1010
+
1011
+ return true;
1012
+ }
1013
+
1014
+ private function isHashElement ($line) {
1015
+ return strpos($line, ':');
1016
+ }
1017
+
1018
+ private function isLiteral ($line) {
1019
+ if ($this->isArrayElement($line)) return false;
1020
+ if ($this->isHashElement($line)) return false;
1021
+ return true;
1022
+ }
1023
+
1024
+
1025
+ private static function unquote ($value) {
1026
+ if (!$value) return $value;
1027
+ if (!is_string($value)) return $value;
1028
+ if ($value[0] == '\'') return trim ($value, '\'');
1029
+ if ($value[0] == '"') return trim ($value, '"');
1030
+ return $value;
1031
+ }
1032
+
1033
+ private function startsMappedSequence ($line) {
1034
+ return (substr($line, 0, 2) == '- ' && substr ($line, -1, 1) == ':');
1035
+ }
1036
+
1037
+ private function returnMappedSequence ($line) {
1038
+ $array = array();
1039
+ $key = self::unquote(trim(substr($line,1,-1)));
1040
+ $array[$key] = array();
1041
+ $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key);
1042
+ return array($array);
1043
+ }
1044
+
1045
+ private function checkKeysInValue($value) {
1046
+ if (strchr('[{"\'', $value[0]) === false) {
1047
+ if (strchr($value, ': ') !== false) {
1048
+ throw new Exception('Too many keys: '.$value);
1049
+ }
1050
+ }
1051
+ }
1052
+
1053
+ private function returnMappedValue ($line) {
1054
+ $this->checkKeysInValue($line);
1055
+ $array = array();
1056
+ $key = self::unquote (trim(substr($line,0,-1)));
1057
+ $array[$key] = '';
1058
+ return $array;
1059
+ }
1060
+
1061
+ private function startsMappedValue ($line) {
1062
+ return (substr ($line, -1, 1) == ':');
1063
+ }
1064
+
1065
+ private function isPlainArray ($line) {
1066
+ return ($line[0] == '[' && substr ($line, -1, 1) == ']');
1067
+ }
1068
+
1069
+ private function returnPlainArray ($line) {
1070
+ return $this->_toType($line);
1071
+ }
1072
+
1073
+ private function returnKeyValuePair ($line) {
1074
+ $array = array();
1075
+ $key = '';
1076
+ if (strpos ($line, ': ')) {
1077
+ // It's a key/value pair most likely
1078
+ // If the key is in double quotes pull it out
1079
+ if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
1080
+ $value = trim(str_replace($matches[1],'',$line));
1081
+ $key = $matches[2];
1082
+ } else {
1083
+ // Do some guesswork as to the key and the value
1084
+ $explode = explode(': ', $line);
1085
+ $key = trim(array_shift($explode));
1086
+ $value = trim(implode(': ', $explode));
1087
+ $this->checkKeysInValue($value);
1088
+ }
1089
+ // Set the type of the value. Int, string, etc
1090
+ $value = $this->_toType($value);
1091
+ if ($key === '0') $key = '__!YAMLZero';
1092
+ $array[$key] = $value;
1093
+ } else {
1094
+ $array = array ($line);
1095
+ }
1096
+ return $array;
1097
+
1098
+ }
1099
+
1100
+
1101
+ private function returnArrayElement ($line) {
1102
+ if (strlen($line) <= 1) return array(array()); // Weird %)
1103
+ $array = array();
1104
+ $value = trim(substr($line,1));
1105
+ $value = $this->_toType($value);
1106
+ if ($this->isArrayElement($value)) {
1107
+ $value = $this->returnArrayElement($value);
1108
+ }
1109
+ $array[] = $value;
1110
+ return $array;
1111
+ }
1112
+
1113
+
1114
+ private function nodeContainsGroup ($line) {
1115
+ $symbolsForReference = 'A-z0-9_\-';
1116
+ if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
1117
+ if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
1118
+ if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
1119
+ if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1];
1120
+ if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1];
1121
+ if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1];
1122
+ return false;
1123
+
1124
+ }
1125
+
1126
+ private function addGroup ($line, $group) {
1127
+ if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1);
1128
+ if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1);
1129
+ //print_r ($this->path);
1130
+ }
1131
+
1132
+ private function stripGroup ($line, $group) {
1133
+ $line = trim(str_replace($group, '', $line));
1134
+ return $line;
1135
+ }
1136
+ }
1137
+
1138
+ // Enable use of Spyc from command line
1139
+ // The syntax is the following: php Spyc.php spyc.yaml
1140
+
1141
+ do {
1142
+ if (PHP_SAPI != 'cli') break;
1143
+ if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break;
1144
+ if (empty ($_SERVER['PHP_SELF']) || FALSE === strpos ($_SERVER['PHP_SELF'], 'Spyc.php') ) break;
1145
+ $file = $argv[1];
1146
+ echo json_encode (spyc_load_file ($file));
1147
+ } while (0);
views/icwp-wpsf-access_restricted_index.php CHANGED
@@ -19,29 +19,28 @@ include_once( 'icwp-wpsf-config_header.php' );
19
  }
20
  else {
21
  ?>
22
- <div class="well">
23
  <h3><?php _wpsf_e( 'What should you enter here?');?></h3>
24
- <p><?php _wpsf_e( 'At some point you supplied an Admin Access Key - to manage this plugin, you must supply it here first.');?>.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  </div>
26
- <form action="<?php echo $icwp_form_action; ?>" method="post" class="form-horizontal">
27
- <input type="hidden" name="icwp_wpsf_requested_page" value="<?php echo $icwp_requested_page; ?>" />
28
- <div class="control-group">
29
- <label class="control-label" for="icwp_wpsf_admin_access_key_request"><?php _wpsf_e( 'Enter Access Key');?><br></label>
30
- <div class="controls">
31
- <div class="option_section selected_item active" id="option_section_icwp_wpsf_admin_access_key">
32
- <label>
33
- <input type="text" name="icwp_wpsf_admin_access_key_request" value="" autocomplete="off" />
34
- </label>
35
- <p class="help-block"><?php _wpsf_e( 'To manage this plugin you must enter the access key.');?></p>
36
- </div>
37
- </div><!-- controls -->
38
- </div>
39
- <div class="form-actions">
40
- <?php wp_nonce_field( $icwp_nonce_field ); ?>
41
- <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
42
- <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Submit Key' ); ?></button>
43
- </div>
44
- </form>
45
  <?php
46
  }
47
  ?>
19
  }
20
  else {
21
  ?>
22
+ <div class="well admin_access_restriction_form">
23
  <h3><?php _wpsf_e( 'What should you enter here?');?></h3>
24
+ <p><?php _wpsf_e( 'At some point you supplied an Admin Access Key - to manage this plugin, you must supply it here first.');?></p>
25
+ <form action="<?php echo $icwp_form_action; ?>" method="post" class="form-horizontal">
26
+ <div class="control-group">
27
+ <label class="control-label" for="<?php echo $icwp_var_prefix; ?>admin_access_key_request"><?php _wpsf_e( 'Enter Access Key');?><br></label>
28
+ <div class="controls">
29
+ <div class="option_section selected_item active" id="option_section_icwp_wpsf_admin_access_key">
30
+ <label>
31
+ <input type="text" name="<?php echo $icwp_var_prefix; ?>admin_access_key_request" value="" autocomplete="off" />
32
+ </label>
33
+ <p class="help-block"><?php _wpsf_e( 'To manage this plugin you must enter the access key.');?></p>
34
+ </div>
35
+ </div><!-- controls -->
36
+ </div>
37
+ <div class="form-actions">
38
+ <?php wp_nonce_field( $icwp_nonce_field ); ?>
39
+ <input type="hidden" name="<?php echo $icwp_var_prefix; ?>plugin_form_submit" value="Y" />
40
+ <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Submit Access Key' ); ?></button>
41
+ </div>
42
+ </form>
43
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  <?php
45
  }
46
  ?>
views/icwp-wpsf-audit_trail_viewer_index.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ include_once( 'icwp-wpsf-config_header.php' );
3
+
4
+ $aLogTypes = array(
5
+ 0 => _wpsf__('Info'),
6
+ 1 => _wpsf__('Warning'),
7
+ 2 => _wpsf__('Critical')
8
+ );
9
+
10
+ function printAuditTrailTable( $aAuditData ) {
11
+ if ( empty( $aAuditData ) ) {
12
+ return;
13
+ }
14
+ ?>
15
+ <table class="table table-hover table-striped table-audit_trail">
16
+ <tr>
17
+ <th class="cell-time"><?php _wpsf_e('Time'); ?></th>
18
+ <th class="cell-event"><?php _wpsf_e('Event'); ?></th>
19
+ <th class="cell-message"><?php _wpsf_e('Message'); ?></th>
20
+ <th class="cell-username"><?php _wpsf_e('Username'); ?></th>
21
+ <th class="cell-category"><?php _wpsf_e('Category'); ?></th>
22
+ </tr>
23
+ <?php foreach( $aAuditData as $aAuditEntry ) : ?>
24
+ <tr>
25
+ <td><?php echo date( 'Y/m/d', $aAuditEntry['created_at'] ).'<br />'.date( 'H:i:s', $aAuditEntry['created_at'] ); ?></td>
26
+ <td><?php echo $aAuditEntry['event']; ?></td>
27
+ <td><?php echo $aAuditEntry['message']; ?></td>
28
+ <td><?php echo $aAuditEntry['wp_username']; ?></td>
29
+ <td><?php echo $aAuditEntry['category']; ?></td>
30
+ </tr>
31
+ <?php endforeach; ?>
32
+ </table>
33
+ <?php
34
+ }
35
+ ?>
36
+ <div class="row">
37
+ <div class="<?php echo $icwp_fShowAds? 'span9' : 'span12'; ?>">
38
+
39
+ <h4 class="table-title"><?php _wpsf_e( 'Users' ); ?></h4>
40
+ <?php printAuditTrailTable( $icwp_aAuditDataUsers ); ?>
41
+
42
+ <h4 class="table-title"><?php _wpsf_e( 'Plugins' ); ?></h4>
43
+ <?php printAuditTrailTable( $icwp_aAuditDataPlugins ); ?>
44
+
45
+ <h4 class="table-title"><?php _wpsf_e( 'Themes' ); ?></h4>
46
+ <?php printAuditTrailTable( $icwp_aAuditDataThemes ); ?>
47
+
48
+ <h4 class="table-title"><?php _wpsf_e( 'WordPress' ); ?></h4>
49
+ <?php printAuditTrailTable( $icwp_aAuditDataWordpress ); ?>
50
+
51
+ <h4 class="table-title"><?php _wpsf_e( 'Posts' ); ?></h4>
52
+ <?php printAuditTrailTable( $icwp_aAuditDataPosts ); ?>
53
+
54
+ </div><!-- / span9 -->
55
+
56
+ <?php if ( $icwp_fShowAds ) : ?>
57
+ <div class="span3" id="side_widgets">
58
+ <?php echo getWidgetIframeHtml('side-widgets-wtb'); ?>
59
+ </div>
60
+ <?php endif; ?>
61
+ </div><!-- / row -->
62
+
63
+ <div class="row">
64
+ <div class="span6">
65
+ </div><!-- / span6 -->
66
+ <div class="span6">
67
+ <p></p>
68
+ </div><!-- / span6 -->
69
+ </div><!-- / row -->
70
+ <style>
71
+
72
+ h4.table-title {
73
+ font-size: 20px;
74
+ margin: 20px 0 10px 5px;
75
+ }
76
+ table.table.table-audit_trail {
77
+ border: 2px solid #777777;
78
+ margin-bottom: 40px;
79
+ }
80
+ th.cell-time {
81
+ width: 90px;
82
+ max-width: 90px;
83
+ }
84
+ th.cell-username {
85
+ width: 120px;
86
+ max-width: 120px;
87
+ }
88
+ th.cell-event {
89
+ width: 150px;
90
+ max-width: 150px;
91
+ }
92
+ th.cell-category {
93
+ width: 80px;
94
+ max-width: 80px;
95
+ }
96
+ th.cell-message {
97
+ }
98
+ th {
99
+ background-color: white;
100
+ }
101
+
102
+ tr.row-Warning td {
103
+ background-color: #F2D5AE;
104
+ }
105
+ tr.row-Critical td {
106
+ background-color: #DBAFB0;
107
+ }
108
+ tr.row-log-header td {
109
+ border-top: 2px solid #999 !important;
110
+ }
111
+ td.cell-log-type {
112
+ text-align: right !important;
113
+ }
114
+ td .cell-section {
115
+ display: inline-block;
116
+ }
117
+ td .section-ip {
118
+ width: 68%;
119
+ }
120
+ td .section-timestamp {
121
+ text-align: right;
122
+ width: 28%;
123
+ }
124
+ </style>
125
+
126
+ <?php include_once( 'icwp-wpsf-config_footer.php' );
views/icwp-wpsf-changlog_summary.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <h2><?php _wpsf_e( 'Plugin Change Log Summary'); ?></h2>
2
+ <div class="span6" id="tbs_docs_examples">
3
+ <div class="well">
4
+ <h3><?php printf( _wpsf__('Release v%s'), $sLatestVersionBranch ) ; ?></h3>
5
+ <p><?php printf( _wpsf__('The following summarises the main changes to the plugin in the v%s release'), $sLatestVersionBranch ) ; ?></p>
6
+ <p><?php printf( _wpsf__('%snew%s refers to the absolute latest release.'), '<span class="label">', '</span>' ) ; ?></p>
7
+ <?php
8
+ $aNewLog = array(
9
+ 'ADDED: Options to automatic updates to control where and whether email notifications are sent.',
10
+ 'ADDED: Various fixes and verification of WordPress 3.8 compatibility.',
11
+ 'ADDED: Integration with iControlWP and the automatic updates system.',
12
+ 'ADDED: Better filesystem handling methods.',
13
+ 'ADDED: Better firewall logic for whitelisting rules.',
14
+ 'ADDED: Some new firewall white listing parameters to help with post editing.',
15
+ 'ADDED: Option to run automatic updates upon demand according to your settings',
16
+ 'ADDED: Localization capabilities. All we need now are translators.',
17
+ 'ADDED: Option to mask the WordPress version so the real version is never publicly visible.'
18
+ );
19
+ ?>
20
+ <ul>
21
+ <?php foreach( $aNewLog as $sItem ) : ?>
22
+ <li><span class="label"><?php _wpsf_e('new'); ?></span> <?php echo $sItem; ?></li>
23
+ <?php endforeach; ?>
24
+ </ul>
25
+ <?php
26
+ $aLog = array(
27
+ );
28
+ ?>
29
+ <ul>
30
+ <?php foreach( $aLog as $sItem ) : ?>
31
+ <li><?php echo $sItem; ?></li>
32
+ <?php endforeach; ?>
33
+ </ul>
34
+ </div>
35
+ <div class="well">
36
+ <?php
37
+ $aLog = array(
38
+
39
+ '1.9.x' => array(
40
+ 'ADDED: Block deactivation of plugin if admin access restriction is on.',
41
+ 'ADDED: New feature to manage WordPress Automatic Updates.',
42
+ 'FIXED: Several small bugs and streamlined codebase.',
43
+ ),
44
+ '1.8.x' => array(
45
+ 'ADDED: Admin Access Key Restriction feature.',
46
+ 'ADDED: WordPress Lockdown feature.'
47
+ ),
48
+ '1.7.x' => array(
49
+ 'ADDED: Support for WPMU sites (only manageable as Super Admin).',
50
+ 'CHANGE: Serious performance optimizations and a few bug fixes.',
51
+ ),
52
+ '1.6.x' => array(
53
+ 'ADDED: GASP-based, and further enhanced, SPAM comments filtering functionality.',
54
+ ),
55
+ '1.5.x' => array(
56
+ 'IMPROVED: Whitelisting/Blacklisting operations and options',
57
+ 'NEW Option: Login Protect Dedicated IP Whitelist.',
58
+ 'REMOVED Option: Firewall wp-login.php blocking'
59
+ ),
60
+ '1.4.x' => array(
61
+ 'NEW Option: Plugin will automatically upgrade itself when an update is detected - ensures plugin always remains current.',
62
+ 'Now displays an admin notice when a plugin upgrade is available with a link to immediately update.',
63
+ 'Plugin collision protection: removes collision with All In One WordPress Security.',
64
+ 'Improved Login Cooldown Feature- works more like email throttling as it now uses an extra filesystem-based level of protection.',
65
+ "Fix - Login Cooldown Feature didn't take effect in certain circumstances.",
66
+ 'Brand new plugin options system making them more efficient, easier to manage/update, using fewer WordPress database options',
67
+ 'Huge improvements on database calls and efficiency in loading plugin options'
68
+ ),
69
+ '1.3.x' => array(
70
+ "New Feature - Email Throttle. It will prevent you getting bombarded by 1000s of emails in case you're hit by a bot.",
71
+ "Another Firewall die() option. New option will print a message and uses the wp_die() function instead.",
72
+ "Option to separately log Login Protect features.",
73
+ "Refactored and improved the logging system.",
74
+ "Option to by-pass 2-factor authentication in the case sending the verification email fails.",
75
+ "Login Protect checking now better logs out users immediately with a redirect.",
76
+ "We now escape the log data being printed - just in case there's any HTML/JS etc in there we don't want.",
77
+ "Optimized and cleaned a lot of the option caching code to improve reliability and performance (more to come).",
78
+ ),
79
+
80
+ '1.2.x' => array(
81
+ 'New Feature - Ability to import settings from WordPress Firewall 2 Plugin.',
82
+ 'New Feature - Login Form GASP-based Anti-Bot Protection.',
83
+ 'New Feature - Login Cooldown Interval.',
84
+ 'Performance optimizations.',
85
+ 'UI Cleanup and code improvements.',
86
+ 'Added new Login Protect feature where you can add 2-Factor Authentication to your WordPress user logins.',
87
+ 'Improved method for processing the IP address lists to be more cross-platform reliable.',
88
+ 'Improved .htaccess rules (thanks MickeyRoush).',
89
+ 'Mailing method now uses WP_MAIL.'
90
+ ),
91
+
92
+ '1.1.x' => array(
93
+ 'Option to check Cookies values in firewall testing.',
94
+ 'Ability to whitelist particular pages and their parameters.',
95
+ 'Quite a few improvements made to the reliability of the firewall processing.',
96
+ 'Option to completely ignore logged-in Administrators from the Firewall processing (they wont even trigger logging etc).',
97
+ 'Ability to (un)blacklist and (un)whitelist IP addresses directly from within the log.',
98
+ 'Helpful link to IP WHOIS from within the log.',
99
+ 'Firewall logging now has its own dedicated database table.',
100
+ 'Fix: Block email not showing the IPv4 friendly address.',
101
+ 'You can now specify IP ranges in whitelists and blacklists.',
102
+ 'You can now specify which email address to send the notification emails.',
103
+ "You can now add a comment to IP addresses in the whitelist/blacklist. To do this, write your IP address then type a SPACE and write whatever you want (don't take a new line').",
104
+ 'You can now set to delete ALL firewall settings when you deactivate the plugin.',
105
+ 'Improved formatting of the firewall log.'
106
+ )
107
+ );
108
+ ?>
109
+ <?php foreach( $aLog as $sVersion => $aItems ) : ?>
110
+ <h3><?php printf( _wpsf__('Change log for the v%s release'), $sVersion ); ?></h3>
111
+ <ul>
112
+ <?php foreach( $aItems as $sItem ) : ?>
113
+ <li><?php echo $sItem; ?></li>
114
+ <?php endforeach; ?>
115
+ </ul>
116
+ <?php endforeach; ?>
117
+ </div>
118
+ </div><!-- / span6 -->
views/icwp-wpsf-config-options-table.php CHANGED
@@ -8,7 +8,7 @@
8
  ?>
9
  <div class="form-actions">
10
  <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
11
- <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
12
  <button type="submit" class="btn btn-primary btn-large" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
13
  </div>
14
  </form>
8
  ?>
9
  <div class="form-actions">
10
  <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
11
+ <input type="hidden" name="<?php echo $icwp_var_prefix; ?>plugin_form_submit" value="Y" />
12
  <button type="submit" class="btn btn-primary btn-large" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
13
  </div>
14
  </form>
views/icwp-wpsf-config_autoupdates_index.php CHANGED
@@ -6,7 +6,7 @@ include_once( 'icwp-wpsf-config_header.php' );
6
 
7
  <form action="<?php echo $icwp_form_action; ?>" method="post" class="form-horizontal">
8
 
9
- <?php if ( $fAutoupdatesOn ) : ?>
10
  <legend>Run Updates Now</legend>
11
  <div class="control-group">
12
  <label class="control-label">Run Automatic Updates
@@ -28,7 +28,7 @@ include_once( 'icwp-wpsf-config_header.php' );
28
  ?>
29
  <div class="form-actions">
30
  <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
31
- <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
32
  <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
33
  </div>
34
  </form>
6
 
7
  <form action="<?php echo $icwp_form_action; ?>" method="post" class="form-horizontal">
8
 
9
+ <?php if ( isset ( $fAutoupdatesOn ) && $fAutoupdatesOn ) : ?>
10
  <legend>Run Updates Now</legend>
11
  <div class="control-group">
12
  <label class="control-label">Run Automatic Updates
28
  ?>
29
  <div class="form-actions">
30
  <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
31
+ <input type="hidden" name="<?php echo $icwp_var_prefix; ?>plugin_form_submit" value="Y" />
32
  <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
33
  </div>
34
  </form>
views/icwp-wpsf-config_header.php CHANGED
@@ -2,13 +2,13 @@
2
  include_once( dirname(__FILE__).ICWP_DS.'icwp_options_helper.php' );
3
  include_once( dirname(__FILE__).ICWP_DS.'widgets'.ICWP_DS.'icwp_widgets.php' );
4
 
5
- $sPluginName = 'WordPress Simple Firewall';
6
- $fAdminAccessOn = $icwp_aMainOptions['enable_admin_access_restriction'] == 'Y';
7
- $fFirewallOn = $icwp_aMainOptions['enable_firewall'] == 'Y';
8
- $fLoginProtectOn = $icwp_aMainOptions['enable_login_protect'] == 'Y';
9
- $fCommentsFilteringOn = $icwp_aMainOptions['enable_comments_filter'] == 'Y';
10
- $fLockdownOn = $icwp_aMainOptions['enable_lockdown'] == 'Y';
11
- $fAutoupdatesOn = $icwp_aMainOptions['enable_autoupdates'] == 'Y';
12
 
13
  $sLatestVersionBranch = '2.x.x';
14
  $sOn = _wpsf__( 'On' );
@@ -16,10 +16,10 @@ $sOff = _wpsf__( 'Off' );
16
  ?>
17
 
18
  <div class="wrap">
19
- <div class="bootstrap-wpadmin">
20
  <div class="row">
21
  <div class="span12">
22
- <?php include_once( dirname(__FILE__).'/icwp-wpsf-state_summary.php' ); ?>
23
  </div>
24
  </div>
25
  <?php echo printOptionsPageHeader( $icwp_sFeatureName );
2
  include_once( dirname(__FILE__).ICWP_DS.'icwp_options_helper.php' );
3
  include_once( dirname(__FILE__).ICWP_DS.'widgets'.ICWP_DS.'icwp_widgets.php' );
4
 
5
+ $sPluginName = _wpsf__( 'WordPress Simple Firewall' );
6
+ //$fAdminAccessOn = $icwp_aMainOptions['enable_admin_access_restriction'] == 'Y';
7
+ //$fFirewallOn = $icwp_aMainOptions['enable_firewall'] == 'Y';
8
+ //$fLoginProtectOn = $icwp_aMainOptions['enable_login_protect'] == 'Y';
9
+ //$fCommentsFilteringOn = $icwp_aMainOptions['enable_comments_filter'] == 'Y';
10
+ //$fLockdownOn = $icwp_aMainOptions['enable_lockdown'] == 'Y';
11
+ //$fAutoupdatesOn = $icwp_aMainOptions['enable_autoupdates'] == 'Y';
12
 
13
  $sLatestVersionBranch = '2.x.x';
14
  $sOn = _wpsf__( 'On' );
16
  ?>
17
 
18
  <div class="wrap">
19
+ <div class="bootstrap-wpadmin <?php echo isset($icwp_sFeatureSlug) ? $icwp_sFeatureSlug : ''; ?>">
20
  <div class="row">
21
  <div class="span12">
22
+ <?php include_once( 'icwp-wpsf-state_summary.php' ); ?>
23
  </div>
24
  </div>
25
  <?php echo printOptionsPageHeader( $icwp_sFeatureName );
views/icwp-wpsf-config_plugin_index.php CHANGED
@@ -19,7 +19,7 @@ include_once( 'icwp-wpsf-config_header.php' );
19
  ?>
20
  <div class="form-actions">
21
  <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
22
- <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
23
  <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
24
  </div>
25
  </form>
@@ -42,253 +42,10 @@ include_once( 'icwp-wpsf-config_header.php' );
42
  </div>
43
  </div><!-- / row -->
44
  <?php endif; ?>
45
-
46
- <div class="row" id="tbs_docs">
47
- <h2><?php _wpsf_e( 'Plugin Configuration Summary'); ?></h2>
48
- <div class="span6" id="tbs_docs_shortcodes">
49
- <div class="well">
50
- <h4 style="margin-top:20px;">
51
- <?php printf( _wpsf__('Firewall is %s'), $fFirewallOn ? $sOn : $sOff ); ?>
52
- [ <a href="admin.php?page=icwp-wpsf-firewall"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
53
- <?php if ( $fFirewallOn ) : ?>
54
- <ul>
55
- <li><?php printf( _wpsf__('Firewall logging is %s'), ($icwp_aFirewallOptions['enable_firewall_log'] == 'Y') ? $sOn : $sOff ); ?></li>
56
- <li><?php _wpsf_e( 'When the firewall blocks a visit, it will:'); ?>
57
- <?php
58
- if( $icwp_aFirewallOptions['block_response'] == 'redirect_die' ) {
59
- _wpsf_e( 'Die' );
60
- }
61
- else if ( $icwp_aFirewallOptions['block_response'] == 'redirect_die_message' ) {
62
- _wpsf_e( 'Die with a message' );
63
- }
64
- else if ( $icwp_aFirewallOptions['block_response'] == 'redirect_home' ) {
65
- _wpsf_e( 'Redirect to home page' );
66
- }
67
- else if ( $icwp_aFirewallOptions['block_response'] == 'redirect_404' ) {
68
- _wpsf_e( 'Redirect to 404 page' );
69
- }
70
- else {
71
- _wpsf_e( 'Unknown' );
72
- }
73
- ?>
74
- </li>
75
- <?php if ( isset($icwp_aFirewallOptions['ips_whitelist']['ips']) ) : ?>
76
- <li>
77
- <?php printf( _wpsf__('You have %s whitelisted IP addresses'), count( $icwp_aFirewallOptions['ips_whitelist']['ips'] ) ); ?>
78
- <?php foreach( $icwp_aFirewallOptions['ips_whitelist']['ips'] as $sIp ) : ?>
79
- <br />
80
- <?php printf( _wpsf__('%s labelled as %s'), long2ip($sIp), $icwp_aFirewallOptions['ips_whitelist']['meta'][md5( $sIp )] ); ?>
81
- <?php endforeach; ?>
82
- </li>
83
- <?php endif; ?>
84
-
85
- <?php if ( isset($icwp_aFirewallOptions['ips_blacklist']['ips']) ) : ?>
86
- <li>
87
- <?php printf( _wpsf__('You have %s blacklisted IP addresses'), count( $icwp_aFirewallOptions['ips_blacklist']['ips'] ) ); ?>
88
- <?php foreach( $icwp_aFirewallOptions['ips_blacklist']['ips'] as $sIp ) : ?>
89
- <br />
90
- <?php printf( _wpsf__('%s labelled as %s'), long2ip($sIp), $icwp_aFirewallOptions['ips_blacklist']['meta'][md5( $sIp )] ); ?>
91
- <?php endforeach; ?>
92
- </li>
93
- <?php endif; ?>
94
-
95
- <li><?php printf( _wpsf__('Firewall blocks Directory Traversals: %s'), ($icwp_aFirewallOptions['block_dir_traversal'] == 'Y')? $sOn : $sOff ); ?></li>
96
- <li><?php printf( _wpsf__('Firewall blocks SQL Queries: %s'), ($icwp_aFirewallOptions['block_sql_queries'] == 'Y')? $sOn : $sOff ); ?></li>
97
- <li><?php printf( _wpsf__('Firewall blocks WordPress Specific Terms: %s'), ($icwp_aFirewallOptions['block_wordpress_terms'] == 'Y')? $sOn : $sOff ); ?></li>
98
- <li><?php printf( _wpsf__('Firewall blocks Field Truncation Attacks: %s'), ($icwp_aFirewallOptions['block_field_truncation'] == 'Y')? $sOn : $sOff ); ?></li>
99
- <li><?php printf( _wpsf__('Firewall blocks Directory Traversals: %s'), ($icwp_aFirewallOptions['block_dir_traversal'] == 'Y')? $sOn : $sOff ); ?></li>
100
- <li><?php printf( _wpsf__('Firewall blocks Executable File Uploads: %s'), ($icwp_aFirewallOptions['block_exe_file_uploads'] == 'Y')? $sOn : $sOff ); ?></li>
101
- <li><?php printf( _wpsf__('Firewall blocks Leading Schemas (HTTPS / HTTP): %s'), ($icwp_aFirewallOptions['block_leading_schema'] == 'Y')? $sOn : $sOff ); ?></li>
102
- <li><?php printf( _wpsf__('Firewall Logging is %s'), ($icwp_aFirewallOptions['enable_firewall_log'] == 'Y')? $sOn : $sOff ); ?></li>
103
- </ul>
104
- <?php endif; ?>
105
- <hr/>
106
- <h4 style="margin-top:20px;">
107
- <?php printf( _wpsf__('Login Protection is %s'), $fLoginProtectOn ? $sOn : $sOff ); ?>
108
- [ <a href="admin.php?page=icwp-wpsf-login_protect"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
109
- <?php if ( $fLoginProtectOn ) : ?>
110
- <ul>
111
- <?php if ( isset($icwp_aLoginProtectOptions['ips_whitelist']['ips']) ) : ?>
112
- <li>
113
- <?php printf( _wpsf__('You have %s whitelisted IP addresses'), count( $icwp_aLoginProtectOptions['ips_whitelist']['ips'] ) ); ?>
114
- <?php foreach( $icwp_aLoginProtectOptions['ips_whitelist']['ips'] as $sIp ) : ?>
115
- <br />
116
- <?php printf( _wpsf__('%s labelled as %s'), long2ip($sIp), $icwp_aLoginProtectOptions['ips_whitelist']['meta'][md5( $sIp )] ); ?>
117
- <?php endforeach; ?>
118
- </li>
119
- <?php endif; ?>
120
- <li><?php printf( _wpsf__('Two Factor Login Authentication: %s'), ($icwp_aLoginProtectOptions['enable_two_factor_auth_by_ip'] == 'Y')? $sOn : $sOff ); ?></li>
121
- <li><?php printf( _wpsf__('Two Factor Login By Pass: %s'), ($icwp_aLoginProtectOptions['enable_two_factor_bypass_on_email_fail'] == 'Y')? $sOn : $sOff ); ?></li>
122
- <li><?php printf( _wpsf__('Login Cooldown Interval: %s'), ($icwp_aLoginProtectOptions['login_limit_interval'] == '0')? $sOff : sprintf( _wpsf__('%s seconds'), $icwp_aLoginProtectOptions['login_limit_interval'] ) ); ?></li>
123
- <li><?php printf( _wpsf__('Login Form GASP Protection: %s'), ($icwp_aLoginProtectOptions['enable_login_gasp_check'] == 'Y')? $sOn : $sOff ); ?></li>
124
- <li><?php printf( _wpsf__('Login Protect Logging: %s'), ($icwp_aLoginProtectOptions['enable_login_protect_log'] == 'Y')? $sOn : $sOff ); ?></li>
125
- </ul>
126
- <?php endif; ?>
127
- <hr/>
128
- <h4 style="margin-top:20px;">
129
- <?php printf( _wpsf__('Comments Filtering is %s'), $fCommentsFilteringOn ? $sOn : $sOff ); ?>
130
- [ <a href="admin.php?page=icwp-wpsf-comments_filter"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
131
- <?php if ( $fCommentsFilteringOn ) : ?>
132
- <ul>
133
- <li><?php printf( _wpsf__('Enchanced GASP Protection: %s'), ($icwp_aCommentsFilterOptions['enable_comments_gasp_protection'] == 'Y')? $sOn : $sOff ); ?></li>
134
- <li><?php printf( _wpsf__('Comments Cooldown Interval: %s'), ($icwp_aCommentsFilterOptions['comments_cooldown_interval'] == '0')? $sOff : sprintf( _wpsf__('%s seconds'), $icwp_aCommentsFilterOptions['comments_cooldown_interval'] ) ); ?></li>
135
- <li><?php printf( _wpsf__('Comments Token Expire: %s'), ($icwp_aCommentsFilterOptions['comments_token_expire_interval'] == '0')? $sOff : sprintf( _wpsf__('%s seconds'), $icwp_aCommentsFilterOptions['comments_token_expire_interval'] ) ); ?></li>
136
- </ul>
137
- <?php endif; ?>
138
- <hr/>
139
- <h4 style="margin-top:20px;">
140
- <?php printf( _wpsf__('WordPress Lockdown is %s'), $fLockdownOn ? $sOn : $sOff ); ?>
141
- [ <a href="admin.php?page=icwp-wpsf-lockdown"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
142
- <?php if ( $fLockdownOn ) : ?>
143
- <ul>
144
- <li><?php printf( _wpsf__('Disable File Editing: %s'), ($icwp_aLockdownOptions['disable_file_editing'] == 'Y')? $sOn : $sOff ); ?></li>
145
- <li><?php printf( _wpsf__('Mask WordPress Version: %s'), empty($icwp_aLockdownOptions['mask_wordpress_version'])? $sOff : $icwp_aLockdownOptions['mask_wordpress_version'] ); ?></li>
146
- </ul>
147
- <?php endif; ?>
148
- <hr/>
149
- <h4 style="margin-top:20px;">
150
- <?php printf( _wpsf__('Auto Updates is %s'), $fAutoupdatesOn ? $sOn : $sOff ); ?>
151
- [ <a href="admin.php?page=icwp-wpsf-autoupdates"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
152
- <?php if ( $fAutoupdatesOn ) :
153
-
154
- if ( $icwp_aAutoupdatesOptions['autoupdate_core'] == 'core_never' ) {
155
- $sAutoCoreUpdateOption = $sOff;
156
- }
157
- else if ( $icwp_aAutoupdatesOptions['autoupdate_core'] == 'core_minor' ) {
158
- $sAutoCoreUpdateOption = _wpsf__('Minor Versions Only');
159
- }
160
- else {
161
- $sAutoCoreUpdateOption = _wpsf__('Major and Minor Versions');
162
- }
163
- ?>
164
- <ul>
165
- <li><?php printf( _wpsf__('Automatically Update WordPress Simple Firewall Plugin: %s'), ($icwp_aAutoupdatesOptions['autoupdate_plugin_self'] == 'Y')? $sOn : $sOff ); ?></li>
166
- <li><?php printf( _wpsf__('Automatically Update WordPress Core: %s'), $sAutoCoreUpdateOption ); ?></li>
167
- <li><?php printf( _wpsf__('Automatically Update Plugins: %s'), ($icwp_aAutoupdatesOptions['enable_autoupdate_plugins'] == 'Y')? $sOn : $sOff ); ?></li>
168
- <li><?php printf( _wpsf__('Automatically Update Themes: %s'), ($icwp_aAutoupdatesOptions['enable_autoupdate_themes'] == 'Y')? $sOn : $sOff ); ?></li>
169
- <li><?php printf( _wpsf__('Automatically Update Translations: %s'), ($icwp_aAutoupdatesOptions['enable_autoupdate_translations'] == 'Y')? $sOn : $sOff ); ?></li>
170
- <li><?php printf( _wpsf__('Ignore Version Control Systems: %s'), ($icwp_aAutoupdatesOptions['enable_autoupdate_ignore_vcs'] == 'Y')? $sOn : $sOff ); ?></li>
171
- </ul>
172
- <?php endif; ?>
173
- </div>
174
- </div><!-- / span6 -->
175
- <div class="span6" id="tbs_docs_examples">
176
- <div class="well">
177
- <h3><?php printf( _wpsf__('Release v%s'), $sLatestVersionBranch ) ; ?></h3>
178
- <p><?php printf( _wpsf__('The following summarises the main changes to the plugin in the v%s release'), $sLatestVersionBranch ) ; ?></p>
179
- <p><?php printf( _wpsf__('%snew%s refers to the absolute latest release.'), '<span class="label">', '</span>' ) ; ?></p>
180
- <?php
181
- $aNewLog = array(
182
- 'ADDED: Options to automatic updates to control where and whether email notifications are sent.',
183
- 'ADDED: Various fixes and verification of WordPress 3.8 compatibility.',
184
- 'ADDED: Integration with iControlWP and the automatic updates system.',
185
- 'ADDED: Better filesystem handling methods.',
186
- 'ADDED: Better firewall logic for whitelisting rules.',
187
- 'ADDED: Some new firewall white listing parameters to help with post editing.',
188
- 'ADDED: Option to run automatic updates upon demand according to your settings',
189
- 'ADDED: Localization capabilities. All we need now are translators.',
190
- 'ADDED: Option to mask the WordPress version so the real version is never publicly visible.'
191
- );
192
- ?>
193
- <ul>
194
- <?php foreach( $aNewLog as $sItem ) : ?>
195
- <li><span class="label"><?php _wpsf_e('new'); ?></span> <?php echo $sItem; ?></li>
196
- <?php endforeach; ?>
197
- </ul>
198
- <?php
199
- $aLog = array(
200
- );
201
- ?>
202
- <ul>
203
- <?php foreach( $aLog as $sItem ) : ?>
204
- <li><?php echo $sItem; ?></li>
205
- <?php endforeach; ?>
206
- </ul>
207
- </div>
208
- <div class="well">
209
- <?php
210
- $aLog = array(
211
 
212
- '1.9.x' => array(
213
- 'ADDED: Block deactivation of plugin if admin access restriction is on.',
214
- 'ADDED: New feature to manage WordPress Automatic Updates.',
215
- 'FIXED: Several small bugs and streamlined codebase.',
216
- ),
217
- '1.8.x' => array(
218
- 'ADDED: Admin Access Key Restriction feature.',
219
- 'ADDED: WordPress Lockdown feature.'
220
- ),
221
- '1.7.x' => array(
222
- 'ADDED: Support for WPMU sites (only manageable as Super Admin).',
223
- 'CHANGE: Serious performance optimizations and a few bug fixes.',
224
- ),
225
- '1.6.x' => array(
226
- 'ADDED: GASP-based, and further enhanced, SPAM comments filtering functionality.',
227
- ),
228
- '1.5.x' => array(
229
- 'IMPROVED: Whitelisting/Blacklisting operations and options',
230
- 'NEW Option: Login Protect Dedicated IP Whitelist.',
231
- 'REMOVED Option: Firewall wp-login.php blocking'
232
- ),
233
- '1.4.x' => array(
234
- 'NEW Option: Plugin will automatically upgrade itself when an update is detected - ensures plugin always remains current.',
235
- 'Now displays an admin notice when a plugin upgrade is available with a link to immediately update.',
236
- 'Plugin collision protection: removes collision with All In One WordPress Security.',
237
- 'Improved Login Cooldown Feature- works more like email throttling as it now uses an extra filesystem-based level of protection.',
238
- "Fix - Login Cooldown Feature didn't take effect in certain circumstances.",
239
- 'Brand new plugin options system making them more efficient, easier to manage/update, using fewer WordPress database options',
240
- 'Huge improvements on database calls and efficiency in loading plugin options'
241
- ),
242
- '1.3.x' => array(
243
- "New Feature - Email Throttle. It will prevent you getting bombarded by 1000s of emails in case you're hit by a bot.",
244
- "Another Firewall die() option. New option will print a message and uses the wp_die() function instead.",
245
- "Option to separately log Login Protect features.",
246
- "Refactored and improved the logging system.",
247
- "Option to by-pass 2-factor authentication in the case sending the verification email fails.",
248
- "Login Protect checking now better logs out users immediately with a redirect.",
249
- "We now escape the log data being printed - just in case there's any HTML/JS etc in there we don't want.",
250
- "Optimized and cleaned a lot of the option caching code to improve reliability and performance (more to come).",
251
- ),
252
-
253
- '1.2.x' => array(
254
- 'New Feature - Ability to import settings from WordPress Firewall 2 Plugin.',
255
- 'New Feature - Login Form GASP-based Anti-Bot Protection.',
256
- 'New Feature - Login Cooldown Interval.',
257
- 'Performance optimizations.',
258
- 'UI Cleanup and code improvements.',
259
- 'Added new Login Protect feature where you can add 2-Factor Authentication to your WordPress user logins.',
260
- 'Improved method for processing the IP address lists to be more cross-platform reliable.',
261
- 'Improved .htaccess rules (thanks MickeyRoush).',
262
- 'Mailing method now uses WP_MAIL.'
263
- ),
264
-
265
- '1.1.x' => array(
266
- 'Option to check Cookies values in firewall testing.',
267
- 'Ability to whitelist particular pages and their parameters.',
268
- 'Quite a few improvements made to the reliability of the firewall processing.',
269
- 'Option to completely ignore logged-in Administrators from the Firewall processing (they wont even trigger logging etc).',
270
- 'Ability to (un)blacklist and (un)whitelist IP addresses directly from within the log.',
271
- 'Helpful link to IP WHOIS from within the log.',
272
- 'Firewall logging now has its own dedicated database table.',
273
- 'Fix: Block email not showing the IPv4 friendly address.',
274
- 'You can now specify IP ranges in whitelists and blacklists.',
275
- 'You can now specify which email address to send the notification emails.',
276
- "You can now add a comment to IP addresses in the whitelist/blacklist. To do this, write your IP address then type a SPACE and write whatever you want (don't take a new line').",
277
- 'You can now set to delete ALL firewall settings when you deactivate the plugin.',
278
- 'Improved formatting of the firewall log.'
279
- )
280
- );
281
- ?>
282
- <?php foreach( $aLog as $sVersion => $aItems ) : ?>
283
- <h3><?php printf( _wpsf__('Change log for the v%s release'), $sVersion ); ?></h3>
284
- <ul>
285
- <?php foreach( $aItems as $sItem ) : ?>
286
- <li><?php echo $sItem; ?></li>
287
- <?php endforeach; ?>
288
- </ul>
289
- <?php endforeach; ?>
290
- </div>
291
- </div><!-- / span6 -->
292
  </div><!-- / row -->
293
 
294
  <div class="row">
19
  ?>
20
  <div class="form-actions">
21
  <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
22
+ <input type="hidden" name="<?php echo $icwp_var_prefix; ?>plugin_form_submit" value="Y" />
23
  <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
24
  </div>
25
  </form>
42
  </div>
43
  </div><!-- / row -->
44
  <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ <div class="row" id="tbs_docs">
47
+ <?php // include_once( 'icwp-wpsf-config_summary.php' ); ?>
48
+ <?php // include_once( 'icwp-wpsf-changlog_summary.php' ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  </div><!-- / row -->
50
 
51
  <div class="row">
views/icwp-wpsf-config_summary.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <h2><?php _wpsf_e( 'Plugin Configuration Summary'); ?></h2>
2
+ <div class="span6" id="tbs_docs_shortcodes">
3
+ <div class="well">
4
+ <h4 style="margin-top:20px;">
5
+ <?php printf( _wpsf__('Firewall is %s'), $fFirewallOn ? $sOn : $sOff ); ?>
6
+ [ <a href="admin.php?page=icwp-wpsf-firewall"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
7
+ <?php if ( $fFirewallOn ) : ?>
8
+ <ul>
9
+ <li><?php printf( _wpsf__('Firewall logging is %s'), ($icwp_aFirewallOptions['enable_firewall_log'] == 'Y') ? $sOn : $sOff ); ?></li>
10
+ <li><?php _wpsf_e( 'When the firewall blocks a visit, it will:'); ?>
11
+ <?php
12
+ if( $icwp_aFirewallOptions['block_response'] == 'redirect_die' ) {
13
+ _wpsf_e( 'Die' );
14
+ }
15
+ else if ( $icwp_aFirewallOptions['block_response'] == 'redirect_die_message' ) {
16
+ _wpsf_e( 'Die with a message' );
17
+ }
18
+ else if ( $icwp_aFirewallOptions['block_response'] == 'redirect_home' ) {
19
+ _wpsf_e( 'Redirect to home page' );
20
+ }
21
+ else if ( $icwp_aFirewallOptions['block_response'] == 'redirect_404' ) {
22
+ _wpsf_e( 'Redirect to 404 page' );
23
+ }
24
+ else {
25
+ _wpsf_e( 'Unknown' );
26
+ }
27
+ ?>
28
+ </li>
29
+ <?php if ( isset($icwp_aFirewallOptions['ips_whitelist']['ips']) ) : ?>
30
+ <li>
31
+ <?php printf( _wpsf__('You have %s whitelisted IP addresses'), count( $icwp_aFirewallOptions['ips_whitelist']['ips'] ) ); ?>
32
+ <?php foreach( $icwp_aFirewallOptions['ips_whitelist']['ips'] as $sIp ) : ?>
33
+ <br />
34
+ <?php printf( _wpsf__('%s labelled as %s'), long2ip($sIp), $icwp_aFirewallOptions['ips_whitelist']['meta'][md5( $sIp )] ); ?>
35
+ <?php endforeach; ?>
36
+ </li>
37
+ <?php endif; ?>
38
+
39
+ <?php if ( isset($icwp_aFirewallOptions['ips_blacklist']['ips']) ) : ?>
40
+ <li>
41
+ <?php printf( _wpsf__('You have %s blacklisted IP addresses'), count( $icwp_aFirewallOptions['ips_blacklist']['ips'] ) ); ?>
42
+ <?php foreach( $icwp_aFirewallOptions['ips_blacklist']['ips'] as $sIp ) : ?>
43
+ <br />
44
+ <?php printf( _wpsf__('%s labelled as %s'), long2ip($sIp), $icwp_aFirewallOptions['ips_blacklist']['meta'][md5( $sIp )] ); ?>
45
+ <?php endforeach; ?>
46
+ </li>
47
+ <?php endif; ?>
48
+
49
+ <li><?php printf( _wpsf__('Firewall blocks Directory Traversals: %s'), ($icwp_aFirewallOptions['block_dir_traversal'] == 'Y')? $sOn : $sOff ); ?></li>
50
+ <li><?php printf( _wpsf__('Firewall blocks SQL Queries: %s'), ($icwp_aFirewallOptions['block_sql_queries'] == 'Y')? $sOn : $sOff ); ?></li>
51
+ <li><?php printf( _wpsf__('Firewall blocks WordPress Specific Terms: %s'), ($icwp_aFirewallOptions['block_wordpress_terms'] == 'Y')? $sOn : $sOff ); ?></li>
52
+ <li><?php printf( _wpsf__('Firewall blocks Field Truncation Attacks: %s'), ($icwp_aFirewallOptions['block_field_truncation'] == 'Y')? $sOn : $sOff ); ?></li>
53
+ <li><?php printf( _wpsf__('Firewall blocks Directory Traversals: %s'), ($icwp_aFirewallOptions['block_dir_traversal'] == 'Y')? $sOn : $sOff ); ?></li>
54
+ <li><?php printf( _wpsf__('Firewall blocks Executable File Uploads: %s'), ($icwp_aFirewallOptions['block_exe_file_uploads'] == 'Y')? $sOn : $sOff ); ?></li>
55
+ <li><?php printf( _wpsf__('Firewall blocks Leading Schemas (HTTPS / HTTP): %s'), ($icwp_aFirewallOptions['block_leading_schema'] == 'Y')? $sOn : $sOff ); ?></li>
56
+ <li><?php printf( _wpsf__('Firewall Logging is %s'), ($icwp_aFirewallOptions['enable_firewall_log'] == 'Y')? $sOn : $sOff ); ?></li>
57
+ </ul>
58
+ <?php endif; ?>
59
+ <hr/>
60
+ <h4 style="margin-top:20px;">
61
+ <?php printf( _wpsf__('Login Protection is %s'), $fLoginProtectOn ? $sOn : $sOff ); ?>
62
+ [ <a href="admin.php?page=icwp-wpsf-login_protect"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
63
+ <?php if ( $fLoginProtectOn ) : ?>
64
+ <ul>
65
+ <?php if ( isset($icwp_aLoginProtectOptions['ips_whitelist']['ips']) ) : ?>
66
+ <li>
67
+ <?php printf( _wpsf__('You have %s whitelisted IP addresses'), count( $icwp_aLoginProtectOptions['ips_whitelist']['ips'] ) ); ?>
68
+ <?php foreach( $icwp_aLoginProtectOptions['ips_whitelist']['ips'] as $sIp ) : ?>
69
+ <br />
70
+ <?php printf( _wpsf__('%s labelled as %s'), long2ip($sIp), $icwp_aLoginProtectOptions['ips_whitelist']['meta'][md5( $sIp )] ); ?>
71
+ <?php endforeach; ?>
72
+ </li>
73
+ <?php endif; ?>
74
+ <li><?php printf( _wpsf__('Two Factor Login Authentication: %s'), ($icwp_aLoginProtectOptions['enable_two_factor_auth_by_ip'] == 'Y')? $sOn : $sOff ); ?></li>
75
+ <li><?php printf( _wpsf__('Two Factor Login By Pass: %s'), ($icwp_aLoginProtectOptions['enable_two_factor_bypass_on_email_fail'] == 'Y')? $sOn : $sOff ); ?></li>
76
+ <li><?php printf( _wpsf__('Login Cooldown Interval: %s'), ($icwp_aLoginProtectOptions['login_limit_interval'] == '0')? $sOff : sprintf( _wpsf__('%s seconds'), $icwp_aLoginProtectOptions['login_limit_interval'] ) ); ?></li>
77
+ <li><?php printf( _wpsf__('Login Form GASP Protection: %s'), ($icwp_aLoginProtectOptions['enable_login_gasp_check'] == 'Y')? $sOn : $sOff ); ?></li>
78
+ <li><?php printf( _wpsf__('Login Protect Logging: %s'), ($icwp_aLoginProtectOptions['enable_login_protect_log'] == 'Y')? $sOn : $sOff ); ?></li>
79
+ </ul>
80
+ <?php endif; ?>
81
+ <hr/>
82
+ <h4 style="margin-top:20px;">
83
+ <?php printf( _wpsf__('Comments Filtering is %s'), $fCommentsFilteringOn ? $sOn : $sOff ); ?>
84
+ [ <a href="admin.php?page=icwp-wpsf-comments_filter"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
85
+ <?php if ( $fCommentsFilteringOn ) : ?>
86
+ <ul>
87
+ <li><?php printf( _wpsf__('Enchanced GASP Protection: %s'), ($icwp_aCommentsFilterOptions['enable_comments_gasp_protection'] == 'Y')? $sOn : $sOff ); ?></li>
88
+ <li><?php printf( _wpsf__('Comments Cooldown Interval: %s'), ($icwp_aCommentsFilterOptions['comments_cooldown_interval'] == '0')? $sOff : sprintf( _wpsf__('%s seconds'), $icwp_aCommentsFilterOptions['comments_cooldown_interval'] ) ); ?></li>
89
+ <li><?php printf( _wpsf__('Comments Token Expire: %s'), ($icwp_aCommentsFilterOptions['comments_token_expire_interval'] == '0')? $sOff : sprintf( _wpsf__('%s seconds'), $icwp_aCommentsFilterOptions['comments_token_expire_interval'] ) ); ?></li>
90
+ </ul>
91
+ <?php endif; ?>
92
+ <hr/>
93
+ <h4 style="margin-top:20px;">
94
+ <?php printf( _wpsf__('WordPress Lockdown is %s'), $fLockdownOn ? $sOn : $sOff ); ?>
95
+ [ <a href="admin.php?page=icwp-wpsf-lockdown"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
96
+ <?php if ( $fLockdownOn ) : ?>
97
+ <ul>
98
+ <li><?php printf( _wpsf__('Disable File Editing: %s'), ($icwp_aLockdownOptions['disable_file_editing'] == 'Y')? $sOn : $sOff ); ?></li>
99
+ <li><?php printf( _wpsf__('Mask WordPress Version: %s'), empty($icwp_aLockdownOptions['mask_wordpress_version'])? $sOff : $icwp_aLockdownOptions['mask_wordpress_version'] ); ?></li>
100
+ </ul>
101
+ <?php endif; ?>
102
+ <hr/>
103
+ <h4 style="margin-top:20px;">
104
+ <?php printf( _wpsf__('Auto Updates is %s'), $fAutoupdatesOn ? $sOn : $sOff ); ?>
105
+ [ <a href="admin.php?page=icwp-wpsf-autoupdates"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
106
+ <?php if ( $fAutoupdatesOn ) :
107
+
108
+ if ( $icwp_aAutoupdatesOptions['autoupdate_core'] == 'core_never' ) {
109
+ $sAutoCoreUpdateOption = $sOff;
110
+ }
111
+ else if ( $icwp_aAutoupdatesOptions['autoupdate_core'] == 'core_minor' ) {
112
+ $sAutoCoreUpdateOption = _wpsf__('Minor Versions Only');
113
+ }
114
+ else {
115
+ $sAutoCoreUpdateOption = _wpsf__('Major and Minor Versions');
116
+ }
117
+ ?>
118
+ <ul>
119
+ <li><?php printf( _wpsf__('Automatically Update WordPress Simple Firewall Plugin: %s'), ($icwp_aAutoupdatesOptions['autoupdate_plugin_self'] == 'Y')? $sOn : $sOff ); ?></li>
120
+ <li><?php printf( _wpsf__('Automatically Update WordPress Core: %s'), $sAutoCoreUpdateOption ); ?></li>
121
+ <li><?php printf( _wpsf__('Automatically Update Plugins: %s'), ($icwp_aAutoupdatesOptions['enable_autoupdate_plugins'] == 'Y')? $sOn : $sOff ); ?></li>
122
+ <li><?php printf( _wpsf__('Automatically Update Themes: %s'), ($icwp_aAutoupdatesOptions['enable_autoupdate_themes'] == 'Y')? $sOn : $sOff ); ?></li>
123
+ <li><?php printf( _wpsf__('Automatically Update Translations: %s'), ($icwp_aAutoupdatesOptions['enable_autoupdate_translations'] == 'Y')? $sOn : $sOff ); ?></li>
124
+ <li><?php printf( _wpsf__('Ignore Version Control Systems: %s'), ($icwp_aAutoupdatesOptions['enable_autoupdate_ignore_vcs'] == 'Y')? $sOn : $sOff ); ?></li>
125
+ </ul>
126
+ <?php endif; ?>
127
+ </div>
128
+ </div><!-- / span6 -->
views/icwp-wpsf-config_user_management_index.php CHANGED
@@ -34,7 +34,9 @@ function printSessionTable( $aSessionsData ) {
34
  ?>
35
  <div class="row">
36
  <div class="span12">
37
- <h2><?php _wpsf_e('Current User Sessions');?></h2>
 
 
38
  <?php if ( !empty($icwp_aActiveSessions) ) : ?>
39
  <?php printSessionTable($icwp_aActiveSessions); ?>
40
  <?php else : ?>
34
  ?>
35
  <div class="row">
36
  <div class="span12">
37
+ <h2><?php _wpsf_e('Current User Sessions'); ?>
38
+ <small>(<?php echo sprintf( _wpsf__( 'now: %s' ), date( 'Y/m/d H:i:s', time() ) ) ?>)</small>
39
+ </h2>
40
  <?php if ( !empty($icwp_aActiveSessions) ) : ?>
41
  <?php printSessionTable($icwp_aActiveSessions); ?>
42
  <?php else : ?>
views/{icwp_wpsf_firewall_log_index.php → icwp-wpsf-firewall_log_index.php} RENAMED
@@ -14,7 +14,7 @@ $aLogTypes = array(
14
  wp_nonce_field( $icwp_nonce_field );
15
  ?>
16
  <div class="form-actions">
17
- <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
18
  <button type="submit" class="btn btn-primary" name="clear_log_submit" value="1"><?php _wpsf_e( 'Clear/Fix Log' ); ?></button>
19
  </div>
20
  </form>
14
  wp_nonce_field( $icwp_nonce_field );
15
  ?>
16
  <div class="form-actions">
17
+ <input type="hidden" name="<?php echo $icwp_var_prefix; ?>plugin_form_submit" value="Y" />
18
  <button type="submit" class="btn btn-primary" name="clear_log_submit" value="1"><?php _wpsf_e( 'Clear/Fix Log' ); ?></button>
19
  </div>
20
  </form>
views/{icwp_wpsf_privacy_protect_log_index.php → icwp-wpsf-privacy_protect_log_index.php} RENAMED
@@ -9,7 +9,7 @@ $icwp_fShowAds = false;
9
  wp_nonce_field( $icwp_nonce_field );
10
  ?>
11
  <div class="form-actions">
12
- <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
13
  <button type="submit" class="btn btn-primary" name="clear_log_submit"><?php _wpsf_e( 'Clear/Fix Log' ); ?></button>
14
  </div>
15
  </form>
9
  wp_nonce_field( $icwp_nonce_field );
10
  ?>
11
  <div class="form-actions">
12
+ <input type="hidden" name="<?php echo $icwp_var_prefix; ?>plugin_form_submit" value="Y" />
13
  <button type="submit" class="btn btn-primary" name="clear_log_submit"><?php _wpsf_e( 'Clear/Fix Log' ); ?></button>
14
  </div>
15
  </form>
views/icwp_options_helper.php CHANGED
@@ -25,12 +25,14 @@ function printAllPluginOptionsForm( $inaAllPluginOptions, $insVarPrefix = '', $i
25
 
26
  //Take each Options Section in turn
27
  foreach ( $inaAllPluginOptions as $sOptionSection ) {
28
-
 
 
29
  $sRowId = str_replace( ' ', '', $sOptionSection['section_title'] );
30
  //Print the Section Title
31
  echo '
32
- <div class="row" id="'.$sRowId.'">
33
- <div class="span9" style="margin-left:0px">
34
  <fieldset>
35
  <legend>'.$sOptionSection['section_title'].'</legend>
36
  ';
@@ -69,22 +71,44 @@ function printAllPluginOptionsForm( $inaAllPluginOptions, $insVarPrefix = '', $i
69
 
70
  }
71
 
72
- function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
73
 
74
- list( $sOptionKey, $sOptionSaved, $sOptionDefault, $mOptionType, $sOptionHumanName, $sOptionTitle, $sOptionHelpText, $sHelpLink ) = array_pad( $inaOption, 8, '' );
 
 
 
 
 
 
 
 
 
 
75
  if ( $sOptionKey == 'spacer' ) {
76
  $sHtml = '
77
- <div class="span'.$iSpanSize.'">
78
  </div>
79
  ';
80
- } else {
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
- $sHelpLink = !empty($sHelpLink)? '<span>['.$sHelpLink.']</span>' : '';
83
  $sSpanId = 'span_'.$insVarPrefix.$sOptionKey;
84
  $sHtml = '
85
- <div class="item_group span'.$iSpanSize.' '.( ($sOptionSaved === 'Y' || $sOptionSaved != $sOptionDefault )? ' selected_item_group':'' ).'" id="'.$sSpanId.'">
86
  <div class="control-group">
87
- <label class="control-label" for="'.$insVarPrefix.$sOptionKey.'">'.$sOptionHumanName.'<br />'.$sHelpLink.'</label>
88
  <div class="controls">
89
  <div class="option_section'.( ($sOptionSaved == 'Y')? ' selected_item':'' ).'" id="option_section_'.$insVarPrefix.$sOptionKey.'">
90
  <label>
@@ -92,7 +116,7 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
92
  $sAdditionalClass = '';
93
  $sHelpSection = '';
94
 
95
- if ( $mOptionType === 'checkbox' ) {
96
 
97
  $sChecked = ( $sOptionSaved == 'Y' )? 'checked="checked"' : '';
98
 
@@ -106,7 +130,7 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
106
  '.$sOptionTitle;
107
 
108
  }
109
- else if ( $mOptionType === 'text' ) {
110
  $sTextInput = esc_attr( $sOptionSaved );
111
  $sHtml .= '
112
  <p>'.$sOptionTitle.'</p>
@@ -117,7 +141,7 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
117
  id="'.$insVarPrefix.$sOptionKey.'"
118
  class="span5" />';
119
  }
120
- else if ( $mOptionType === 'password' ) {
121
  $sTextInput = esc_attr( $sOptionSaved );
122
  $sHtml .= '
123
  <p>'.$sOptionTitle.'</p>
@@ -128,7 +152,7 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
128
  id="'.$insVarPrefix.$sOptionKey.'"
129
  class="span5" />';
130
  }
131
- else if ( $mOptionType === 'email' ) {
132
  $sTextInput = esc_attr( $sOptionSaved );
133
  $sHtml .= '
134
  <p>'.$sOptionTitle.'</p>
@@ -140,60 +164,44 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
140
  class="span5" />';
141
 
142
  }
143
- else if ( is_array($mOptionType) ) { //it's a select, or radio
144
 
145
- if ( isset( $mOptionType['type'] ) ) {
146
- $sInputType = $mOptionType['type'];
147
- unset( $mOptionType['type'] );
148
- }
149
- else {
150
- $sInputType = array_shift($mOptionType);
151
- }
152
-
153
- if ( $sInputType == 'select' ) {
154
-
155
- $sFragment = '<p>'.$sOptionTitle.'</p>
156
  <select
157
  id="'.$insVarPrefix.$sOptionKey.'"
158
  name="'.$insVarPrefix.$sOptionKey.'">';
159
 
160
- foreach( $mOptionType as $aInput ) {
161
-
162
- list( $mOptionValue, $sOptionName ) = $aInput;
163
- $fSelected = $sOptionSaved == $mOptionValue;
164
 
165
- $sFragment .= '
 
166
  <option
167
  value="'.$mOptionValue.'"
168
  id="'.$insVarPrefix.$sOptionKey.'_'.$mOptionValue.'"'
169
- .( $fSelected? ' selected="selected"' : '') .'>'. $sOptionName.'</option>';
170
- }
171
- $sFragment .= '</select>';
172
-
173
  }
174
- if ( $sInputType == 'multiple_select' ) {
 
 
 
175
 
176
- $sFragment = '<p>'.$sOptionTitle.'</p>
177
  <select
178
  id="'.$insVarPrefix.$sOptionKey.'"
179
- name="'.$insVarPrefix.$sOptionKey.'[]" multiple multiple="multiple" size="'.count($mOptionType).'">';
180
-
181
- foreach( $mOptionType as $mOptionValue => $sOptionName ) {
182
 
183
- $fSelected = in_array( $mOptionValue, $sOptionSaved );
184
 
185
- $sFragment .= '
186
- <option
187
  value="'.$mOptionValue.'"
188
  id="'.$insVarPrefix.$sOptionKey.'_'.$mOptionValue.'"'
189
- .( $fSelected? ' selected="selected"' : '') .'>'. $sOptionName.'</option>';
190
- }
191
- $sFragment .= '</select>';
192
  }
193
-
194
  $sHtml .= $sFragment;
195
  }
196
- else if ( $mOptionType === 'ip_addresses' ) {
197
  $sTextInput = esc_attr( $sOptionSaved );
198
  $nRows = substr_count( $sTextInput, "\n" ) + 1;
199
  $sHtml .= '
@@ -208,7 +216,7 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
208
  $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
209
 
210
  }
211
- else if ( $mOptionType === 'yubikey_unique_keys' ) {
212
  $sTextInput = esc_attr( $sOptionSaved );
213
  $nRows = substr_count( $sTextInput, "\n" ) + 1;
214
  $sHtml .= '
@@ -223,7 +231,7 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
223
  $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
224
 
225
  }
226
- else if ( $mOptionType === 'comma_separated_lists' ) {
227
  $sTextInput = esc_attr( $sOptionSaved );
228
  $nRows = substr_count( $sTextInput, "\n" ) + 1;
229
  $sHtml .= '
@@ -235,7 +243,7 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
235
  rows="'.$nRows.'"
236
  class="span5">'.$sTextInput.'</textarea>';
237
  }
238
- else if ( $mOptionType === 'integer' ) {
239
  $sTextInput = esc_attr( $sOptionSaved );
240
  $sHtml .= '
241
  <p>'.$sOptionTitle.'</p>
25
 
26
  //Take each Options Section in turn
27
  foreach ( $inaAllPluginOptions as $sOptionSection ) {
28
+
29
+ $fIsPrimarySection = isset( $sOptionSection['section_primary'] ) && $sOptionSection['section_primary'];
30
+
31
  $sRowId = str_replace( ' ', '', $sOptionSection['section_title'] );
32
  //Print the Section Title
33
  echo '
34
+ <div class="row option_section_row '.( $fIsPrimarySection? 'primary_section' : 'non_primary_section' ).'" id="'.$sRowId.'">
35
+ <div class="span'.( $fIsPrimarySection? '9' : '9' ).'">
36
  <fieldset>
37
  <legend>'.$sOptionSection['section_title'].'</legend>
38
  ';
71
 
72
  }
73
 
74
+ function getPluginOptionSpan( $aOption, $nSpanSize, $insVarPrefix = '' ) {
75
 
76
+ $sOptionKey = $aOption['key'];
77
+ $sOptionSaved = $aOption['value'];
78
+ $sOptionDefault = $aOption['default'];
79
+ $sOptionType = $aOption['type'];
80
+ $aPossibleOptions = $aOption['value_options'];
81
+ $sHelpLink = $aOption['info_link'];
82
+ $sBlogLink = $aOption['blog_link'];
83
+ $sOptionHumanName = $aOption['name'];
84
+ $sOptionTitle = $aOption['summary'];
85
+ $sOptionHelpText = $aOption['description'];
86
+
87
  if ( $sOptionKey == 'spacer' ) {
88
  $sHtml = '
89
+ <div class="span'.$nSpanSize.'">
90
  </div>
91
  ';
92
+ }
93
+ else {
94
+
95
+ $sLink = '';
96
+ $sLinkTemplate = '<br /><span>[%s]</span>';
97
+ if ( !empty($sHelpLink) ) {
98
+ $sLink = sprintf( $sLinkTemplate, '<a href="'.$sHelpLink.'" target="_blank">'._wpsf__('More Info').'</a>%s' );
99
+ if ( !empty( $sBlogLink ) ) {
100
+ $sLink = sprintf( $sLink, ' | <a href="'.$sBlogLink.'" target="_blank">'._wpsf__('Blog').'</a>' );
101
+ }
102
+ else {
103
+ $sLink = sprintf( $sLink, '' );
104
+ }
105
+ }
106
 
 
107
  $sSpanId = 'span_'.$insVarPrefix.$sOptionKey;
108
  $sHtml = '
109
+ <div class="item_group span'.$nSpanSize.' '.( ($sOptionSaved === 'Y' || $sOptionSaved != $sOptionDefault )? ' selected_item_group':'' ).'" id="'.$sSpanId.'">
110
  <div class="control-group">
111
+ <label class="control-label" for="'.$insVarPrefix.$sOptionKey.'">'.$sOptionHumanName.$sLink.'</label>
112
  <div class="controls">
113
  <div class="option_section'.( ($sOptionSaved == 'Y')? ' selected_item':'' ).'" id="option_section_'.$insVarPrefix.$sOptionKey.'">
114
  <label>
116
  $sAdditionalClass = '';
117
  $sHelpSection = '';
118
 
119
+ if ( $sOptionType === 'checkbox' ) {
120
 
121
  $sChecked = ( $sOptionSaved == 'Y' )? 'checked="checked"' : '';
122
 
130
  '.$sOptionTitle;
131
 
132
  }
133
+ else if ( $sOptionType === 'text' ) {
134
  $sTextInput = esc_attr( $sOptionSaved );
135
  $sHtml .= '
136
  <p>'.$sOptionTitle.'</p>
141
  id="'.$insVarPrefix.$sOptionKey.'"
142
  class="span5" />';
143
  }
144
+ else if ( $sOptionType === 'password' ) {
145
  $sTextInput = esc_attr( $sOptionSaved );
146
  $sHtml .= '
147
  <p>'.$sOptionTitle.'</p>
152
  id="'.$insVarPrefix.$sOptionKey.'"
153
  class="span5" />';
154
  }
155
+ else if ( $sOptionType === 'email' ) {
156
  $sTextInput = esc_attr( $sOptionSaved );
157
  $sHtml .= '
158
  <p>'.$sOptionTitle.'</p>
164
  class="span5" />';
165
 
166
  }
167
+ else if ( $sOptionType === 'select' ) {
168
 
169
+ $sFragment = '<p>'.$sOptionTitle.'</p>
 
 
 
 
 
 
 
 
 
 
170
  <select
171
  id="'.$insVarPrefix.$sOptionKey.'"
172
  name="'.$insVarPrefix.$sOptionKey.'">';
173
 
174
+ foreach( $aPossibleOptions as $mOptionValue => $sOptionName ) {
 
 
 
175
 
176
+ $fSelected = $sOptionSaved == $mOptionValue;
177
+ $sFragment .= '
178
  <option
179
  value="'.$mOptionValue.'"
180
  id="'.$insVarPrefix.$sOptionKey.'_'.$mOptionValue.'"'
181
+ .( $fSelected? ' selected="selected"' : '') .'>'. $sOptionName.'</option>';
 
 
 
182
  }
183
+ $sFragment .= '</select>';
184
+ $sHtml .= $sFragment;
185
+ }
186
+ else if ( $sOptionType === 'multiple_select' ) {
187
 
188
+ $sFragment = '<p>'.$sOptionTitle.'</p>
189
  <select
190
  id="'.$insVarPrefix.$sOptionKey.'"
191
+ name="'.$insVarPrefix.$sOptionKey.'[]" multiple multiple="multiple" size="'.count( $aPossibleOptions ).'">';
 
 
192
 
193
+ foreach( $aPossibleOptions as $mOptionValue => $sOptionName ) {
194
 
195
+ $fSelected = in_array( $mOptionValue, $sOptionSaved );
196
+ $sFragment .= '<option
197
  value="'.$mOptionValue.'"
198
  id="'.$insVarPrefix.$sOptionKey.'_'.$mOptionValue.'"'
199
+ .( $fSelected? ' selected="selected"' : '') .'>'. $sOptionName.'</option>';
 
 
200
  }
201
+ $sFragment .= '</select>';
202
  $sHtml .= $sFragment;
203
  }
204
+ else if ( $sOptionType === 'ip_addresses' ) {
205
  $sTextInput = esc_attr( $sOptionSaved );
206
  $nRows = substr_count( $sTextInput, "\n" ) + 1;
207
  $sHtml .= '
216
  $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
217
 
218
  }
219
+ else if ( $sOptionType === 'yubikey_unique_keys' ) {
220
  $sTextInput = esc_attr( $sOptionSaved );
221
  $nRows = substr_count( $sTextInput, "\n" ) + 1;
222
  $sHtml .= '
231
  $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
232
 
233
  }
234
+ else if ( $sOptionType === 'comma_separated_lists' ) {
235
  $sTextInput = esc_attr( $sOptionSaved );
236
  $nRows = substr_count( $sTextInput, "\n" ) + 1;
237
  $sHtml .= '
243
  rows="'.$nRows.'"
244
  class="span5">'.$sTextInput.'</textarea>';
245
  }
246
+ else if ( $sOptionType === 'integer' ) {
247
  $sTextInput = esc_attr( $sOptionSaved );
248
  $sHtml .= '
249
  <p>'.$sOptionTitle.'</p>
views/icwp_wpsf_index.php CHANGED
@@ -23,7 +23,7 @@ include_once( 'icwp-wpsf-config_header.php' );
23
  ?>
24
  <div class="form-actions">
25
  <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
26
- <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
27
  <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
28
  </div>
29
  </form>
23
  ?>
24
  <div class="form-actions">
25
  <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
26
+ <input type="hidden" name="<?php echo $icwp_var_prefix; ?>plugin_form_submit" value="Y" />
27
  <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
28
  </div>
29
  </form>
views/include_js.php CHANGED
@@ -34,7 +34,7 @@
34
  }
35
  );
36
 
37
- jQuery( 'select[name=<?php echo $worpit_var_prefix; ?>option]' ).trigger( 'change' );
38
  }
39
  );
40
 
34
  }
35
  );
36
 
37
+ jQuery( 'select[name=<?php echo $icwp_var_prefix; ?>option]' ).trigger( 'change' );
38
  }
39
  );
40
 
views/snippets/admin_notice_mailchimp.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <!-- Begin MailChimp Signup Form -->
3
+ <div id="mc_embed_signup">
4
+ <form class="form form-inline" action="http://hostliketoast.us2.list-manage1.com/subscribe/post?u=e736870223389e44fb8915c9a&amp;id=0e1d527259" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
5
+ <p>The WordPress Simple Firewall team has launched a education initiative to raise awareness of WordPress security and to provide further help with the WordPress Simple Firewall plugin. Get Involved here:</p>
6
+ <input type="text" value="" name="EMAIL" class="required email" id="mce-EMAIL" placeholder="Your Email" />
7
+ <input type="text" value="" name="FNAME" class="" id="mce-FNAME" placeholder="Your Name" />
8
+ <input type="hidden" value="<?php echo $nDays; ?>" name="DAYS" class="" id="mce-DAYS" />
9
+ <input type="submit" value="Get The News" name="subscribe" id="mc-embedded-subscribe" class="button" />
10
+ <a href="<?php echo $sLink_HideNotice;?>">Dismiss</a>
11
+ <div id="mce-responses" class="clear">
12
+ <div class="response" id="mce-error-response" style="display:none"></div>
13
+ <div class="response" id="mce-success-response" style="display:none"></div>
14
+ </div> <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
15
+ <div style="position: absolute; left: -5000px;"><input type="text" name="b_e736870223389e44fb8915c9a_0e1d527259" tabindex="-1" value=""></div>
16
+ <div class="clear"></div>
17
+ </form>
18
+ </div>
views/snippets/admin_notice_override.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+
2
+ <!-- Begin MailChimp Signup Form -->
3
+ <h3><?php echo sprintf( _wpsf__('Warning - %s.'), _wpsf__('The Simple Firewall is not currently running' ) ); ?></h3>
4
+ <p><?php echo sprintf( _wpsf__('Please delete the "%s" file to reactivate the Firewall processing' ), 'forceOff' );?></p>
views/snippets/admin_notice_plugin_upgraded.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <form method="post" action="<?php echo $sAction; ?>">
2
+ <input type="hidden" value="<?php echo $sRedirectPage; ?>" name="redirect_page" id="redirect_page">
3
+ <p><?php echo $sMessage; ?></p>
4
+ <input type="submit" value="<?php echo $sButtonText; ?>" name="submit" class="button" style="float:left; margin-bottom:10px;">
5
+ <div style="clear:both;"></div>
6
+ </form>
views/snippets/admin_notice_translate_plugin.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="IcwpTranslationsNotice">
2
+ <form method="post" action="<?php echo $sAction; ?>">
3
+ <input type="hidden" value="<?php echo $sRedirectPage; ?>" name="redirect_page" id="redirect_page">
4
+ <h4 style="margin:10px 0 3px;">
5
+ <?php _wpsf_e( 'Would you like to help translate the WordPress Simple Firewall into your language?' ); ?>
6
+ <?php printf( _wpsf__( 'Head over to: %s' ), '<a href="http://translate.icontrolwp.com" target="_blank">translate.icontrolwp.com</a>' ); ?>
7
+ </h4>
8
+ <input type="submit" value="<?php _wpsf_e( 'Dismiss this notice' ); ?>" name="submit" class="button" style="float:left; margin-bottom:10px;">
9
+ <div style="clear:both;"></div>
10
+ </form>
11
+ </div>