Shield Security for WordPress - Version 2.6.6

Version Description

  • FIX: Improved compatibility with bbPress.
Download this release

Release Info

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

Code changes from version 2.0.0 to 2.6.6

Files changed (59) hide show
  1. icwp-wpsf.php +561 -932
  2. languages/wp-simple-firewall-ca_ES.mo +0 -0
  3. languages/wp-simple-firewall-es_ES.mo +0 -0
  4. languages/wp-simple-firewall-fa_IR.mo +0 -0
  5. languages/wp-simple-firewall-he_IL.mo +0 -0
  6. languages/wp-simple-firewall-it_IT.mo +0 -0
  7. languages/wp-simple-firewall-pt_BR.mo +0 -0
  8. languages/wp-simple-firewall-tr_TR.mo +0 -0
  9. readme.txt +207 -30
  10. resources/css/{bootstrap-wpadmin.css → bootstrap-wpadmin-legacy.css} +0 -0
  11. resources/css/{icontrolwp-plugin.css → plugin.css} +20 -5
  12. resources/css/worpit-plugin.css +0 -119
  13. resources/images/icontrolwp_16x16.png +0 -0
  14. resources/images/icontrolwp_24x24.png +0 -0
  15. resources/images/icontrolwp_32x32.png +0 -0
  16. resources/images/pluginlogo_16x16.png +0 -0
  17. resources/images/pluginlogo_24x24.png +0 -0
  18. resources/images/pluginlogo_32x32.png +0 -0
  19. resources/images/pluginlogo_64x64.png +0 -0
  20. resources/spamblacklist.txt +10549 -0
  21. src/icwp-base-processor.php +111 -59
  22. src/icwp-basedb-processor.php +136 -6
  23. src/icwp-data-processor.php +198 -4
  24. src/icwp-feature-master.php +337 -0
  25. src/icwp-import-base-processor.php +2 -2
  26. src/icwp-import-wpf2-processor.php +3 -3
  27. src/icwp-once.php +49 -0
  28. src/icwp-optionshandler-autoupdates.php +51 -20
  29. src/icwp-optionshandler-base.php +156 -60
  30. src/icwp-optionshandler-commentsfilter.php +122 -21
  31. src/icwp-optionshandler-email.php +90 -0
  32. src/icwp-optionshandler-firewall.php +87 -51
  33. src/icwp-optionshandler-lockdown.php +44 -20
  34. src/icwp-optionshandler-logging.php +59 -0
  35. src/icwp-optionshandler-loginprotect.php +163 -26
  36. src/icwp-optionshandler-privacyprotect.php +99 -0
  37. src/icwp-optionshandler-wpsf.php +65 -90
  38. src/icwp-plugins-base.php +0 -692
  39. src/icwp-processor-autoupdates.php +248 -33
  40. src/icwp-processor-commentsfilter.php +355 -90
  41. src/icwp-processor-email.php +42 -16
  42. src/icwp-processor-firewall.php +114 -85
  43. src/icwp-processor-lockdown.php +47 -28
  44. src/icwp-processor-logging.php +33 -21
  45. src/icwp-processor-loginprotect.php +544 -146
  46. src/icwp-processor-privacyprotect.php +173 -0
  47. src/icwp-pure-base.php +966 -0
  48. src/icwp-wpfilesystem.php +126 -16
  49. src/icwp-wpfunctions.php +59 -7
  50. src/icwp-wpsf-stats.php +77 -0
  51. views/icwp_options_helper.php +81 -44
  52. views/icwp_wpsf_config_autoupdates_index.php +15 -1
  53. views/icwp_wpsf_config_login_protect_index.php +1 -0
  54. views/icwp_wpsf_config_privacy_protect_index.php +35 -0
  55. views/icwp_wpsf_firewall_log_index.php +0 -1
  56. views/icwp_wpsf_index.php +30 -18
  57. views/icwp_wpsf_privacy_protect_log_index.php +93 -0
  58. views/icwp_wpsf_state_summary.php +115 -0
  59. views/widgets/icwp_widgets.php +10 -12
icwp-wpsf.php CHANGED
@@ -3,14 +3,14 @@
3
  * Plugin Name: WordPress Simple Firewall
4
  * Plugin URI: http://icwp.io/2f
5
  * Description: A Simple WordPress Firewall
6
- * Version: 2.0.0
7
  * Text Domain: wp-simple-firewall
8
  * Author: iControlWP
9
  * Author URI: http://icwp.io/2e
10
  */
11
 
12
  /**
13
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
14
  * All rights reserved.
15
  *
16
  * "WordPress Simple Firewall" is
@@ -30,7 +30,7 @@
30
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
  */
32
 
33
- require_once( dirname(__FILE__).'/src/icwp-plugins-base.php' );
34
  require_once( dirname(__FILE__).'/src/icwp-data-processor.php' );
35
 
36
  if ( !function_exists( '_wpsf_e' ) ) {
@@ -46,22 +46,27 @@ if ( !function_exists( '_wpsf__' ) ) {
46
 
47
  if ( !class_exists('ICWP_Wordpress_Simple_Firewall') ):
48
 
49
- class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
50
-
51
- const InputPrefix = 'icwp_wpsf_';
52
- const OptionPrefix = 'icwp_wpsf_'; //ALL database options use this as the prefix.
53
- const AdminAccessKeyCookieName = "icwp_wpsf_aakcook";
 
 
54
 
 
 
 
 
55
  /**
56
  * Should be updated each new release.
57
  * @var string
58
  */
59
- static public $VERSION = '2.0.0';
60
-
61
  /**
62
- * @var ICWP_OptionsHandler_Wpsf
63
  */
64
- protected $m_oWpsfOptions;
65
 
66
  /**
67
  * @var ICWP_OptionsHandler_Firewall
@@ -72,6 +77,10 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
72
  * @var ICWP_OptionsHandler_LoginProtect
73
  */
74
  protected $m_oLoginProtectOptions;
 
 
 
 
75
 
76
  /**
77
  * @var ICWP_OptionsHandler_CommentsFilter
@@ -87,6 +96,11 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
87
  * @var ICWP_OptionsHandler_AutoUpdates
88
  */
89
  protected $m_oAutoUpdatesOptions;
 
 
 
 
 
90
 
91
  /**
92
  * @var ICWP_FirewallProcessor
@@ -102,19 +116,23 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
102
  * @var ICWP_CommentsFilterProcessor
103
  */
104
  protected $m_oCommentsFilterProcessor;
105
-
106
  /**
107
  * @var ICWP_LockdownProcessor
108
  */
109
  protected $m_oLockdownProcessor;
 
 
 
 
110
 
111
  /**
112
- * @var ICWP_AutoUpdatesProcessor
113
  */
114
  protected $m_oAutoUpdatesProcessor;
115
 
116
  /**
117
- * @var ICWP_LoggingProcessor
118
  */
119
  protected $m_oLoggingProcessor;
120
 
@@ -122,330 +140,99 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
122
  * @var ICWP_EmailProcessor
123
  */
124
  protected $m_oEmailProcessor;
125
-
 
 
 
 
 
 
 
126
  public function __construct() {
127
 
128
  $this->m_fNetworkAdminOnly = true;
129
- parent::__construct();
130
-
131
- register_activation_hook( __FILE__, array( $this, 'onWpActivatePlugin' ) );
132
- register_deactivation_hook( __FILE__, array( $this, 'onWpDeactivatePlugin' ) );
133
- // register_uninstall_hook( __FILE__, array( &$this, 'onWpUninstallPlugin' ) );
134
-
135
- self::$PLUGIN_HUMAN_NAME = "WordPress Simple Firewall";
136
- self::$PLUGIN_NAME = basename(__FILE__);
137
- self::$PLUGIN_PATH = plugin_basename( dirname(__FILE__) );
138
- self::$PLUGIN_FILE = plugin_basename(__FILE__);
139
- self::$PLUGIN_DIR = WP_PLUGIN_DIR.ICWP_DS.self::$PLUGIN_PATH.ICWP_DS;
140
- self::$PLUGIN_URL = plugins_url( '/', __FILE__ ) ;
141
- self::$OPTION_PREFIX = self::OptionPrefix;
142
-
143
- $this->m_sParentMenuIdSuffix = 'wpsf';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  // loads the base plugin options from 1 db call
145
- $this->loadOptionsHandler( 'Wpsf' );
146
- $this->m_fAutoPluginUpgrade = false && $this->m_oWpsfOptions->getOpt( 'enable_auto_plugin_upgrade' ) == 'Y';
147
 
148
  // checks for filesystem based firewall overrides
149
  $this->override();
150
-
151
- if ( $this->getIsMainFeatureEnabled( 'firewall' ) ) {
152
- add_action( 'plugins_loaded', array( $this, 'runFirewallProcess' ), 1 );
153
- }
154
-
155
- if ( $this->getIsMainFeatureEnabled( 'login_protect' ) ) {
156
- add_action( 'plugins_loaded', array( $this, 'runLoginProtect' ), 1 );
157
- }
158
-
159
- if ( $this->getIsMainFeatureEnabled( 'comments_filter' ) ) {
160
- add_action( 'plugins_loaded', array( $this, 'runCommentsFilter' ), 1 );
161
- }
162
-
163
- if ( $this->getIsMainFeatureEnabled( 'lockdown' ) ) {
164
- add_action( 'plugins_loaded', array( $this, 'runLockdown' ), 1 );
165
- }
166
-
167
- if ( $this->getIsMainFeatureEnabled( 'autoupdates' ) ) {
168
- add_action( 'plugins_loaded', array( $this, 'runAutoUpdates' ), 1 );
169
- }
170
-
171
- add_action( 'in_plugin_update_message-'.self::$PLUGIN_FILE, array( $this, 'onWpPluginUpdateMessage' ) );
172
 
173
  if ( isset( $_GET['turnoffperm'] ) ) {
174
  $this->setPermissionToSubmit( false );
175
  }
176
- }
177
-
178
- /**
179
- * Load the multilingual aspect of the plugin
180
- */
181
- public function load_textdomain() {
182
- load_plugin_textdomain( 'wp-simple-firewall', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
183
- }
184
-
185
- public function removePluginConflicts() {
186
- if ( class_exists('AIO_WP_Security') && isset( $GLOBALS['aio_wp_security'] ) ) {
187
- remove_action( 'init', array( $GLOBALS['aio_wp_security'], 'wp_security_plugin_init'), 0 );
188
- }
189
- }
190
-
191
- /**
192
- */
193
- public function onWpInit() {
194
- parent::onWpInit();
195
- add_action( 'plugin_action_links', array( $this, 'onWpPluginActionLinks' ), 10, 4 );
196
- }
197
-
198
- /**
199
- * @param array $aPlugins
200
- * @return unknown
201
- */
202
- public function hide_plugin( $inaPlugins ) {
203
- foreach ( $inaPlugins as $sSlug => $aData ) {
204
- if ( strpos( $sSlug, 'icwp-wpsf.php' ) !== false ) {
205
- unset( $inaPlugins[$sSlug] );
206
- }
207
- }
208
- return $inaPlugins;
209
- }
210
-
211
- protected function override() {
212
- if ( is_file( self::$PLUGIN_DIR . 'forceOff' ) ) {
213
- $this->setSharedOption( 'enable_firewall', 'N' );
214
- $this->setSharedOption( 'enable_login_protect', 'N' );
215
- $this->setSharedOption( 'enable_comments_filter', 'N' );
216
- $this->setSharedOption( 'enable_autoupdates', 'N' );
217
- $this->setSharedOption( 'enable_admin_access_restriction', 'N' );
218
- }
219
- else if ( is_file( self::$PLUGIN_DIR . 'forceOn' ) ) {
220
- $this->setSharedOption( 'enable_firewall', 'Y' );
221
- $this->setSharedOption( 'enable_login_protect', 'Y' );
222
- $this->setSharedOption( 'enable_comments_filter', 'Y' );
223
- $this->setSharedOption( 'enable_autoupdates', 'Y' );
224
- $this->setSharedOption( 'enable_admin_access_restriction', 'Y' );
225
- }
226
- else {
227
- return true;
228
- }
229
- $this->resetFirewallProcessor();
230
- $this->resetLoginProcessor();
231
- }
232
-
233
- protected function genSecretKey() {
234
- $sKey = $this->m_oWpsfOptions->getOpt( 'secret_key' );
235
- if ( empty( $sKey ) ) {
236
- $sKey = md5( mt_rand() );
237
- $this->m_oWpsfOptions->setOpt( 'secret_key', $sKey );
238
- }
239
- return $sKey;
240
- }
241
-
242
- protected function getFeaturesMap() {
243
- return array(
244
- 'firewall' => 'Firewall',
245
- 'login_protect' => 'LoginProtect',
246
- 'comments_filter' => 'CommentsFilter',
247
- 'lockdown' => 'Lockdown',
248
- 'autoupdates' => 'AutoUpdates'
249
- );
250
- }
251
-
252
- /**
253
- * @param string $insFeature - firewall, login_protect, comments_filter, lockdown
254
- * @return boolean
255
- */
256
- public function getIsMainFeatureEnabled( $insFeature ) {
257
-
258
- if ( is_file( self::$PLUGIN_DIR . 'forceOff' ) ) {
259
- return false;
260
- }
261
- else if ( is_file( self::$PLUGIN_DIR . 'forceOn' ) ) {
262
- return true;
263
- }
264
-
265
- $aFeatures = $this->getFeaturesMap();
266
-
267
- switch ( $insFeature ) {
268
- case 'admin_access':
269
- $fEnabled = $this->m_oWpsfOptions->getOpt( 'enable_admin_access_restriction' ) == 'Y';
270
- break;
271
- default:
272
- if ( array_key_exists( $insFeature, $aFeatures ) ) {
273
- $fEnabled = $this->m_oWpsfOptions->getOpt( 'enable_'.$insFeature ) == 'Y';
274
- }
275
- else {
276
- $fEnabled = false;
277
- }
278
- break;
279
- }
280
- return $fEnabled;
281
- }
282
-
283
- /**
284
- * This is necessary because we store these values in several places and we need to always keep it in sync.
285
- *
286
- * @param string $sFeature
287
- * @param boolean $infEnabled
288
- * @return boolean
289
- */
290
- public function setSharedOption( $insOption, $inmValue ) {
291
 
292
- $aFeatures = $this->getFeaturesMap();
293
-
294
- $sFeature = str_replace( 'enable_', '', $insOption );
295
- if ( !array_key_exists( $sFeature, $aFeatures ) ) {
296
- return;
297
- }
298
-
299
- $this->loadOptionsHandler( $aFeatures[$sFeature] );
300
- $sOptions = 'm_o'.$aFeatures[$sFeature].'Options';// e.g. m_oFirewallOptions
301
- $this->{$sOptions}->setOpt( $insOption, $inmValue );
302
- $this->m_oWpsfOptions->setOpt( $insOption, $inmValue );
303
  }
304
-
305
  /**
306
- * Updates the current log data with new data.
307
- *
308
- * @param array $inaNewLogData
309
- * @return boolean
310
  */
311
- protected function updateLogStore() {
312
-
313
- if ( isset( $this->m_oFirewallProcessor ) && is_object( $this->m_oFirewallProcessor ) && $this->getIsMainFeatureEnabled( 'firewall' ) ) {
314
- $aLogData = $this->m_oFirewallProcessor->flushLogData();
315
- if ( !is_null( $aLogData ) && !empty( $aLogData ) ) {
316
- $this->loadProcessor( 'Logging' );
317
- $this->m_oLoggingProcessor->writeLog( $aLogData );
318
- }
319
- }
320
-
321
- if ( isset( $this->m_oLoginProtectProcessor ) && is_object( $this->m_oLoginProtectProcessor ) && $this->getIsMainFeatureEnabled( 'login_protect' ) ) {
322
- $aLogData = $this->m_oLoginProtectProcessor->flushLogData();
323
- if ( !is_null( $aLogData ) && !empty( $aLogData ) ) {
324
- $this->loadProcessor( 'Logging' );
325
- $this->m_oLoggingProcessor->writeLog( $aLogData );
326
- }
327
- }
328
- }
329
-
330
- protected function loadOptionsHandler( $insOptionHandler, $infFullBuild = false ) {
331
-
332
- $aAllHandlers = array_values( $this->getFeaturesMap() );
333
- $aAllHandlers[] = 'Wpsf';
334
-
335
- // special case
336
- if ( $insOptionHandler == 'all' ) {
337
- foreach( $aAllHandlers as $sHandler ) {
338
- $this->loadOptionsHandler( $sHandler, $infFullBuild );
339
- }
340
- return;
341
- }
342
-
343
- if ( !in_array( $insOptionHandler, $aAllHandlers ) ) {
344
- wp_die( 'Options handler is not permitted: '.$insOptionHandler );
345
- }
346
-
347
- $sOptionsVarName = 'm_o'.$insOptionHandler.'Options'; // e.g. m_oWpsfOptions
348
- $sSourceFile = dirname(__FILE__).'/src/icwp-optionshandler-'.strtolower($insOptionHandler).'.php'; // e.g. icwp-optionshandler-wpsf.php
349
- $sClassName = 'ICWP_OptionsHandler_'.$insOptionHandler; // e.g. ICWP_OptionsHandler_Wpsf
350
-
351
- require_once( $sSourceFile );
352
- if ( !isset( $this->{$sOptionsVarName} ) ) {
353
- $this->{$sOptionsVarName} = new $sClassName( self::OptionPrefix, self::$VERSION, $infFullBuild );
354
- }
355
- if ( $infFullBuild ) {
356
- $this->{$sOptionsVarName}->buildOptions();
357
- }
358
- }
359
-
360
- protected function loadProcessor( $insProcessorName, $infReset = false ) {
361
-
362
- $aAllProcessors = array(
363
- 'Firewall' => 'firewall',
364
- 'LoginProtect' => 'login',
365
- 'CommentsFilter' => 'comments',
366
- 'Lockdown' => 'lockdown',
367
- 'AutoUpdates' => 'autoupdates',
368
- 'Logging' => '',
369
- 'Email' => ''
370
- );
371
-
372
- if ( !array_key_exists( $insProcessorName, $aAllProcessors ) ) {
373
- wp_die( 'Processor is not permitted here.' );
374
- }
375
-
376
- $sProcessorVarName = 'm_o'.$insProcessorName.'Processor'; // e.g. m_oFirewallProcessor
377
- $sSourceFile = dirname(__FILE__).'/src/icwp-processor-'.strtolower($insProcessorName).'.php'; // e.g. icwp-optionshandler-wpsf.php
378
- $sClassName = 'ICWP_'.$insProcessorName.'Processor'; // e.g. ICWP_FirewallProcessor
379
- $sStoredOptionName = $aAllProcessors[$insProcessorName].'_processor'; // e.g. firewall_processor
380
- $sOptionsHandlerVarName = 'm_o'.$insProcessorName.'Options'; // e.g. m_oFirewallOptions
381
-
382
- require_once( $sSourceFile );
383
- if ( empty( $this->{$sProcessorVarName} ) ) {
384
-
385
- $this->{$sProcessorVarName} = self::getOption( $sStoredOptionName );
386
- if ( is_object( $this->{$sProcessorVarName} ) && ( $this->{$sProcessorVarName} instanceof $sClassName ) ) {
387
- $this->{$sProcessorVarName}->reset();
388
- }
389
- else {
390
- $this->{$sProcessorVarName} = new $sClassName();
391
- // Also loads the options handler where appropriate
392
- if ( !empty( $aAllProcessors[ $insProcessorName ] ) ) {
393
- $this->loadOptionsHandler( $insProcessorName );
394
- // $this->{$sProcessorVarName}->setOptionsHandler( $this->{$sOptionsHandlerVarName} );
395
- $this->{$sProcessorVarName}->setOptions( $this->{$sOptionsHandlerVarName}->getPluginOptionsValues() );
396
- }
397
- }
398
- }
399
- else if ( $infReset ) {
400
- $this->{$sProcessorVarName}->reset();
401
- }
402
- // Now we handle any custom processor stuff
403
- if ( $insProcessorName == 'LoginProtect' ) {
404
- $this->m_oLoginProtectProcessor->setSecretKey( $this->genSecretKey() );
405
- }
406
- else if ( $insProcessorName == 'Email' ) {
407
- $this->m_oEmailProcessor->setDefaultRecipientAddress( $this->m_oWpsfOptions->getOpt( 'block_send_email_address' ) );
408
- $this->m_oEmailProcessor->setThrottleLimit( $this->m_oWpsfOptions->getOpt( 'send_email_throttle_limit' ) );
409
- $sSiteName = function_exists( 'get_bloginfo' )? get_bloginfo('name') : '';
410
- $this->m_oEmailProcessor->setSiteName( $sSiteName );
411
  }
 
 
 
412
  }
413
 
414
  /**
415
  * Should be called from the constructor so as to ensure it is called as early as possible.
416
  *
417
- * @param array $inaNewLogData
418
- * @return boolean
419
  */
420
  public function runFirewallProcess() {
421
 
422
- if ( is_super_admin() && $this->getOption( 'whitelist_admins' ) == 'Y' ) {
423
- return;
424
- }
425
-
426
  $this->loadProcessor( 'Firewall' );
427
  $fFirewallBlockUser = !$this->m_oFirewallProcessor->doFirewallCheck();
428
 
429
  if ( $fFirewallBlockUser ) {
430
-
431
  if ( $this->m_oFirewallProcessor->getNeedsEmailHandler() ) {
432
  $this->loadProcessor( 'Email' );
433
  $this->m_oFirewallProcessor->setEmailHandler( $this->m_oEmailProcessor );
434
- $this->m_oFirewallProcessor->doPreFirewallBlock();
435
- $this->m_oEmailProcessor->store( self::getKey( 'email_processor' ) );
436
- }
437
- else {
438
- $this->m_oFirewallProcessor->doPreFirewallBlock();
439
  }
 
440
  }
441
- $this->updateLogStore();
442
- $this->m_oFirewallProcessor->store( self::getKey( 'firewall_processor' ) );
443
 
444
  if ( $fFirewallBlockUser ) {
 
445
  $this->m_oFirewallProcessor->doFirewallBlock();
446
  }
447
-
448
- unset( $this->m_oFirewallProcessor );
449
  }
450
 
451
  /**
@@ -453,251 +240,55 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
453
  */
454
  public function runLoginProtect() {
455
  $this->loadProcessor( 'LoginProtect' );
 
 
456
  $this->m_oLoginProtectProcessor->run();
457
-
458
- // We don't want to load the email handler unless we really need it.
459
- // 29 is just before we'll need it if we do
460
- if ( $this->m_oLoginProtectProcessor->getNeedsEmailHandler() ) {
461
- $this->loadProcessor( 'Email' );
462
- $this->m_oLoginProtectProcessor->setEmailHandler( $this->m_oEmailProcessor );
463
- }
464
- }
465
-
466
- /**
467
- * Handles the running of all Comments Filter processes.
468
- */
469
- public function runCommentsFilter() {
470
- $this->loadProcessor( 'CommentsFilter' );
471
- $this->m_oCommentsFilterProcessor->run();
472
- }
473
-
474
- /**
475
- * Handles the running of all Lockdown processes.
476
- */
477
- public function runLockdown() {
478
- $this->loadProcessor( 'Lockdown' );
479
- $this->m_oLockdownProcessor->run();
480
  }
481
 
482
  /**
483
- * Handles the running of all Lockdown processes.
484
  */
485
  public function runAutoUpdates() {
486
  $this->loadProcessor( 'AutoUpdates' );
487
- $this->m_oAutoUpdatesProcessor->run();
488
- }
489
-
490
- protected function getAllOptions() {
491
- $aOptionNames = array(
492
- 'm_oWpsfOptions',
493
- 'm_oFirewallOptions',
494
- 'm_oLoginProtectOptions',
495
- 'm_oCommentsFilterOptions',
496
- 'm_oLockdownOptions',
497
- 'm_oAutoUpdatesOptions'
498
- );
499
-
500
- $this->loadOptionsHandler('all');
501
- $aOptions = array();
502
- foreach( $aOptionNames as $sName ) {
503
- if ( isset( $this->{$sName} ) ) {
504
- $aOptions[] = &$this->{$sName};
505
- }
506
- }
507
- return $aOptions;
508
- }
509
-
510
- protected function getAllProcessors() {
511
- $aProcessorNames = array(
512
- 'firewall_processor' => 'm_oFirewallProcessor',
513
- 'login_processor' => 'm_oLoginProtectProcessor',
514
- 'comments_processor' => 'm_oCommentsFilterProcessor',
515
- 'lockdown_processor' => 'm_oLockdownProcessor',
516
- 'autoupdates_processor' => 'm_oAutoUpdatesProcessor',
517
- 'logging_processor' => 'm_oLoggingProcessor',
518
- 'email_processor' => 'm_oEmailProcessor'
519
- );
520
- $aProcessors = array();
521
- foreach( $aProcessorNames as $sKey => $sName ) {
522
- if ( isset( $this->{$sName} ) ) {
523
- $aProcessors[$sKey] = &$this->{$sName};
524
- }
525
- }
526
- return $aProcessors;
527
- }
528
-
529
- /**
530
- * Make sure and cache the processors after all is said and done.
531
- */
532
- public function saveProcessors_Action() {
533
-
534
- $this->updateLogStore();
535
-
536
- $aOptions = $this->getAllOptions();
537
- foreach( $aOptions as &$oOption ) {
538
- if ( isset( $oOption ) ) {
539
- $oOption->savePluginOptions();
540
- }
541
- }
542
- $aProcessors = $this->getAllProcessors();
543
- foreach( $aProcessors as $sKey => &$oProcessor ) {
544
- $oProcessor->store( self::getKey( $sKey ) );
545
- }
546
- }
547
-
548
- public function onWpAdminInit() {
549
- parent::onWpAdminInit();
550
-
551
- // If it's a plugin admin page, we do certain things we don't do anywhere else.
552
- if ( $this->isIcwpPluginAdminPage()) {
553
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueueBootstrapAdminCss' ), 99 );
554
- }
555
-
556
- // This is only done on WP Admin loads so as not to affect the front-end and only if the firewall is enabled
557
- if ( $this->getIsMainFeatureEnabled( 'firewall' ) ) {
558
- $this->filterIpLists();
559
- }
560
-
561
- //Multilingual support.
562
- // load_plugin_textdomain( 'icwp-wpsf', false, basename( dirname( __FILE__ ) ) . '/languages' );
563
  }
564
 
565
  protected function createPluginSubMenuItems() {
566
-
567
- if ( !$this->hasPermissionToView() ) {
568
- return;
569
- }
570
-
571
  $this->m_aPluginMenu = array(
572
  //Menu Page Title => Menu Item name, page ID (slug), callback function for this page - i.e. what to do/load.
573
- $this->getSubmenuPageTitle( 'Firewall' ) => array( 'Firewall', $this->getSubmenuId('firewall'), 'onDisplayAll' ),
574
- $this->getSubmenuPageTitle( 'Login Protect' ) => array( 'Login Protect', $this->getSubmenuId('login_protect'), 'onDisplayAll' ),
575
- $this->getSubmenuPageTitle( 'Comments Filter' ) => array( 'Comments Filter', $this->getSubmenuId('comments_filter'), 'onDisplayAll' ),
576
- $this->getSubmenuPageTitle( 'Lockdown' ) => array( 'Lockdown', $this->getSubmenuId('lockdown'), 'onDisplayAll' ),
577
- $this->getSubmenuPageTitle( 'Auto Updates' ) => array( 'Auto Updates', $this->getSubmenuId('autoupdates'), 'onDisplayAll' ),
578
- $this->getSubmenuPageTitle( 'Log' ) => array( 'Log', $this->getSubmenuId('firewall_log'), 'onDisplayAll' )
 
 
579
  );
580
  }
581
 
582
  protected function handlePluginUpgrade() {
583
  parent::handlePluginUpgrade();
584
 
585
- $sCurrentPluginVersion = $this->m_oWpsfOptions->getOpt( 'current_plugin_version' );
586
 
587
- if ( $sCurrentPluginVersion !== self::$VERSION && current_user_can( 'manage_options' ) ) {
588
 
589
- self::deleteOption( 'enable_firewall' );
590
- self::deleteOption( 'enable_login_protect' );
591
- self::deleteOption( 'enable_comments_filter' );
 
 
 
 
 
 
592
 
593
  $this->loadProcessor( 'Logging' );
594
  $this->m_oLoggingProcessor->handleInstallUpgrade( $sCurrentPluginVersion );
595
-
596
- // handles migration to new dedicated options system
597
- $this->loadOptionsHandler( 'all' );
598
 
599
  // clears all the processor caches
600
  $this->clearCaches();
601
-
602
- // delete all the old stuff
603
- $aOldOptionKeys = array (
604
- 'current_plugin_version',
605
- 'feedback_admin_notice',
606
- 'secret_key',
607
- 'block_send_email',
608
- 'block_send_email_address',
609
- 'send_email_throttle_limit',
610
- 'delete_on_deactivate',
611
- 'include_cookie_checks',
612
- 'block_dir_traversal',
613
- 'block_sql_queries',
614
- 'block_wordpress_terms',
615
- 'block_field_truncation',
616
- 'block_exe_file_uploads',
617
- 'block_leading_schema',
618
- 'ips_whitelist',
619
- 'ips_blacklist',
620
- 'page_params_whitelist',
621
- 'block_response',
622
- 'enable_firewall_log',
623
- 'enable_two_factor_auth_by_ip',
624
- 'enable_two_factor_bypass_on_email_fail',
625
- 'login_limit_interval',
626
- 'enable_login_gasp_check',
627
- 'enable_login_protect_log'
628
- );
629
- foreach( $aOldOptionKeys as $sOptionKey ) {
630
- self::deleteOption( $sOptionKey );
631
- }
632
- }//if
633
-
634
- //Someone clicked the button to acknowledge the update
635
- if ( isset( $_POST[self::OptionPrefix.'hide_update_notice'] ) && isset( $_POST['user_id'] ) ) {
636
- $this->updateVersionUserMeta( $_POST['user_id'] );
637
- if ( $this->isShowMarketing() ) {
638
- wp_redirect( admin_url( "admin.php?page=".$this->getFullParentMenuId() ) );
639
- }
640
- else {
641
- wp_redirect( admin_url( $_POST['redirect_page'] ) );
642
- }
643
- }
644
- if ( isset( $_POST[self::OptionPrefix.'hide_translation_notice'] ) && isset( $_POST['user_id'] ) ) {
645
- $this->updateTranslationNoticeShownUserMeta( $_POST['user_id'] );
646
- wp_redirect( admin_url( $_POST['redirect_page'] ) );
647
- }
648
- }
649
-
650
- /**
651
- * Updates the current (or supplied user ID) user meta data with the version of the plugin
652
- *
653
- * @param unknown_type $innId
654
- */
655
- protected function updateVersionUserMeta( $innId = '' ) {
656
- $this->updateUserMeta( 'current_version', self::$VERSION, $innId );
657
- }
658
-
659
- /**
660
- * Updates the current (or supplied user ID) user meta data with the version of the plugin
661
- *
662
- * @param unknown_type $innId
663
- */
664
- protected function updateTranslationNoticeShownUserMeta( $innId = '', $insValue = 'Y' ) {
665
- $this->updateUserMeta( 'plugin_translation_notice', $insValue, $innId );
666
- }
667
-
668
- /**
669
- * Updates the current (or supplied user ID) user meta data with the version of the plugin
670
- *
671
- * @param unknown_type $innId
672
- */
673
- protected function updateUserMeta( $insKey, $inmValue, $innId = null ) {
674
- if ( empty( $innId ) ) {
675
- $oCurrentUser = wp_get_current_user();
676
- if ( !($oCurrentUser instanceof WP_User) ) {
677
- return;
678
- }
679
- $nUserId = $oCurrentUser->ID;
680
- }
681
- else {
682
- $nUserId = $innId;
683
- }
684
- update_user_meta( $nUserId, self::OptionPrefix.$insKey, $inmValue );
685
- }
686
-
687
- public function onWpAdminNotices() {
688
- // Do we have admin priviledges?
689
- if ( !current_user_can( 'manage_options' ) ) {
690
- return;
691
- }
692
- parent::onWpAdminNotices();
693
- $this->adminNoticeOptionsUpdated();
694
-
695
- if ( $this->hasPermissionToView() ) {
696
- $this->adminNoticeVersionUpgrade();
697
- }
698
-
699
- if ( $this->hasPermissionToView() ) {
700
- $this->adminNoticeTranslations();
701
  }
702
  }
703
 
@@ -711,14 +302,21 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
711
  $this->onDisplayAccessKeyRequest();
712
  return;
713
  }
714
-
715
- $sPrefix = 'simple-firewall_page_icwp-wpsf-';
 
 
 
 
716
  $sCurrent = str_replace( $sPrefix, '', current_filter() );
717
-
718
  switch( $sCurrent ) {
719
- case 'toplevel_page_'.self::ParentMenuId.'-wpsf' : //special case
720
  $this->onDisplayMainMenu();
721
  break;
 
 
 
722
  case 'firewall_log' :
723
  $this->onDisplayFirewallLog();
724
  break;
@@ -732,40 +330,30 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
732
  }
733
 
734
  public function onDisplayAccessKeyRequest() {
735
-
736
- // Since this is always called until we have Permission, we have to handle the plugin
737
- // form submission here too.
738
  $aData = array(
739
- 'plugin_url' => self::$PLUGIN_URL,
740
- 'var_prefix' => self::OptionPrefix,
741
  'nonce_field' => $this->getSubmenuId( 'wpsf-access-key' ),
742
- 'form_action' => 'admin.php?page='.$this->getSubmenuId()
743
  );
 
744
  $this->display( 'icwp_wpsf_access_key_request_index', $aData );
745
  }
746
 
747
  public function onDisplayMainMenu() {
748
 
749
- // Just to ensure the nag bar disappears if/when they visit the dashboard
750
- // regardless of clicking the button.
751
- $this->updateVersionUserMeta();
752
-
753
- $this->loadOptionsHandler( 'all' );
754
- $aAvailableOptions = $this->m_oWpsfOptions->getOptions();
755
- $sAllFormInputOptions = $this->m_oWpsfOptions->collateAllFormInputsForAllOptions();
756
 
757
  $aData = array(
758
- 'plugin_url' => self::$PLUGIN_URL,
759
- 'var_prefix' => self::OptionPrefix,
760
  'aAllOptions' => $aAvailableOptions,
761
- 'fShowAds' => $this->isShowMarketing(),
762
  'all_options_input' => $sAllFormInputOptions,
763
- 'nonce_field' => $this->getSubmenuId('wpsf-dashboard'),
764
- 'form_action' => 'admin.php?page='.$this->getSubmenuId()
765
  );
 
 
 
 
766
 
767
- $aData['aMainOptions'] = $this->m_oWpsfOptions->getPluginOptionsValues();
768
-
769
  if ( $this->getIsMainFeatureEnabled('firewall') ) {
770
  $this->loadOptionsHandler( 'Firewall' );
771
  $aData['aFirewallOptions'] = $this->m_oFirewallOptions->getPluginOptionsValues();
@@ -786,87 +374,129 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
786
  $this->loadOptionsHandler( 'AutoUpdates' );
787
  $aData['aAutoUpdatesOptions'] = $this->m_oAutoUpdatesOptions->getPluginOptionsValues();
788
  }
789
-
790
  $this->display( 'icwp_'.$this->m_sParentMenuIdSuffix.'_index', $aData );
791
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
792
 
 
 
 
 
 
 
 
 
 
 
793
  protected function onDisplayFirewallLog() {
794
 
795
  $this->loadOptionsHandler( 'Firewall' );
796
  $aIpWhitelist = $this->m_oFirewallOptions->getOpt( 'ips_whitelist' );
797
  $aIpBlacklist = $this->m_oFirewallOptions->getOpt( 'ips_blacklist' );
798
-
799
  $this->loadProcessor( 'Logging' );
800
 
 
801
  $aData = array(
802
- 'plugin_url' => self::$PLUGIN_URL,
803
- 'var_prefix' => self::OptionPrefix,
804
- 'firewall_log' => $this->m_oLoggingProcessor->getLogs( true ),
805
  'ip_whitelist' => isset( $aIpWhitelist['ips'] )? $aIpWhitelist['ips'] : array(),
806
  'ip_blacklist' => isset( $aIpBlacklist['ips'] )? $aIpBlacklist['ips'] : array(),
807
- 'fShowAds' => $this->isShowMarketing(),
808
- 'nonce_field' => $this->getSubmenuId('firewall_log'),
809
- 'form_action' => 'admin.php?page='.$this->getSubmenuId('firewall_log'),
810
  );
811
-
812
  $this->display( 'icwp_wpsf_firewall_log_index', $aData );
813
  }
814
-
815
  /**
816
  *
817
  * @param ICWP_OptionsHandler_Base_WPSF $inoOptions
818
  * @param string $insSlug
819
  */
820
  protected function onDisplayConfig( $inoOptions, $insSlug ) {
821
-
822
  $aAvailableOptions = $inoOptions->getOptions();
823
  $sAllFormInputOptions = $inoOptions->collateAllFormInputsForAllOptions();
824
 
825
  $aData = array(
826
- 'plugin_url' => self::$PLUGIN_URL,
827
- 'var_prefix' => self::OptionPrefix,
828
- 'fShowAds' => $this->isShowMarketing(),
829
  'aAllOptions' => $aAvailableOptions,
830
  'all_options_input' => $sAllFormInputOptions,
831
- 'nonce_field' => $this->getSubmenuId( $insSlug ),
832
- 'form_action' => 'admin.php?page='.$this->getSubmenuId( $insSlug ),
833
  );
 
834
  $this->display( 'icwp_wpsf_config_'.$insSlug.'_index', $aData );
835
  }
836
-
837
- protected function isPluginFormSubmit() {
 
 
 
838
 
839
- $aPostSubmitOptions = array(
 
 
 
 
840
  'icwp_plugin_form_submit',
841
  'icwp_link_action',
842
  'icwp_wpsf_admin_access_key_request'
843
  );
844
-
845
- foreach( $aPostSubmitOptions as $sOption ) {
846
- if ( isset( $_POST[$sOption] ) || isset( $_GET[$sOption] ) ) {
847
  return true;
848
  }
849
  }
850
- return false;
851
  }
852
 
853
  protected function handlePluginFormSubmit() {
854
-
855
- //should have already been checked, but just to make sure.
856
- if ( !$this->isPluginFormSubmit() ) {
857
- return false;
858
- }
859
-
860
- if ( isset( $_POST['icwp_wpsf_admin_access_key_request'] ) ) {
861
  return $this->handleSubmit_AccessKeyRequest();
862
  }
863
 
864
- if ( !$this->hasPermissionToSubmit() ) {
865
  return false;
866
  }
867
-
868
- if ( isset( $_GET['page'] ) ) {
869
- switch ( $_GET['page'] ) {
 
870
  case $this->getSubmenuId():
871
  $this->handleSubmit_Dashboard();
872
  break;
@@ -888,21 +518,27 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
888
  case $this->getSubmenuId( 'firewall_log' ):
889
  $this->handleSubmit_FirewallLog();
890
  break;
 
 
 
 
 
 
891
  default:
892
  return false;
893
  break;
894
  }
895
  }
896
- $this->resetLoggingProcessor();
897
  return true;
898
  }
899
 
900
  protected function setPermissionToSubmit( $infPermission = false ) {
901
-
902
  if ( $infPermission ) {
903
- $sValue = $this->m_oWpsfOptions->getOpt( 'admin_access_key' );
904
- $sTimeout = $this->m_oWpsfOptions->getOpt( 'admin_access_timeout' ) * 60;
905
- $_COOKIE[ self::AdminAccessKeyCookieName ] = 1;
 
906
  setcookie( self::AdminAccessKeyCookieName, $sValue, time()+$sTimeout, COOKIEPATH, COOKIE_DOMAIN, false );
907
  }
908
  else {
@@ -911,51 +547,57 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
911
  }
912
  }
913
 
914
- /**
915
- * @return boolean
916
- */
917
- protected function hasPermissionToView() {
918
- // For now we just use the submit permissions and we can adapt it later
919
- return $this->hasPermissionToSubmit();
920
- }
921
-
922
  /**
923
  * @return boolean
924
  */
925
  protected function hasPermissionToSubmit() {
926
-
927
- // first a basic admin check
928
- if ( !is_super_admin() ) {
929
- return false;
930
  }
931
-
932
- if ( $this->m_oWpsfOptions->getOpt( 'enable_admin_access_restriction' ) == 'Y' ) {
933
- $sAccessKey = $this->m_oWpsfOptions->getOpt( 'admin_access_key' );
 
 
 
 
934
  if ( !empty( $sAccessKey ) ) {
935
- if ( isset( $_COOKIE[ self::AdminAccessKeyCookieName ] )
936
- // && $_COOKIE[ self::AdminAccessKeyCookieName ] == $sAccessKey
937
- ) {
938
- return true;
939
- }
940
- else {
941
- return false;
942
- }
943
  }
944
  }
945
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
946
  }
947
 
948
  protected function handleSubmit_AccessKeyRequest() {
949
  //Ensures we're actually getting this request from WP.
950
  check_admin_referer( $this->getSubmenuId('wpsf-access-key') );
951
 
952
- $this->loadOptionsHandler( 'Wpsf' );
953
- $sAccessKey = md5( trim( $_POST['icwp_wpsf_admin_access_key_request'] ) );
954
- $sStoredAccessKey = $this->m_oWpsfOptions->getOpt( 'admin_access_key' );
955
 
956
  if ( $sAccessKey === $sStoredAccessKey ) {
957
  $this->setPermissionToSubmit( true );
958
- header( 'Location: '.admin_url('admin.php?page=icwp-wpsf') );
959
  exit();
960
  }
961
  return false;
@@ -963,22 +605,35 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
963
 
964
  protected function handleSubmit_Dashboard() {
965
  //Ensures we're actually getting this request from WP.
966
- check_admin_referer( $this->getSubmenuId('wpsf-dashboard') );
967
 
968
- if ( !isset($_POST[self::OptionPrefix.'all_options_input']) ) {
 
969
  return false;
970
  }
971
 
972
- $this->loadOptionsHandler( 'Wpsf' );
973
- $this->m_oWpsfOptions->updatePluginOptionsFromSubmit( $_POST[self::OptionPrefix.'all_options_input'] );
974
-
975
- $this->setSharedOption( 'enable_firewall', $this->m_oWpsfOptions->getOpt( 'enable_firewall' ) );
976
- $this->setSharedOption( 'enable_login_protect', $this->m_oWpsfOptions->getOpt( 'enable_login_protect' ) );
977
- $this->setSharedOption( 'enable_comments_filter', $this->m_oWpsfOptions->getOpt( 'enable_comments_filter' ) );
978
- $this->setSharedOption( 'enable_lockdown', $this->m_oWpsfOptions->getOpt( 'enable_lockdown' ) );
979
- $this->setSharedOption( 'enable_autoupdates', $this->m_oWpsfOptions->getOpt( 'enable_autoupdates' ) );
980
-
 
 
 
 
 
981
  $this->clearCaches();
 
 
 
 
 
 
 
982
  }
983
 
984
  protected function handleSubmit_FirewallConfig() {
@@ -988,428 +643,402 @@ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Base_Plugin {
988
  if ( isset($_POST[ 'import-wpf2-submit' ] ) ) {
989
  $this->importFromFirewall2Plugin();
990
  }
991
- else if ( !isset($_POST[self::OptionPrefix.'all_options_input']) ) {
992
  return;
993
  }
994
  else {
995
  $this->loadOptionsHandler( 'Firewall' );
996
- $this->m_oFirewallOptions->updatePluginOptionsFromSubmit( $_POST[self::OptionPrefix.'all_options_input'] );
997
  }
998
  $this->setSharedOption( 'enable_firewall', $this->m_oFirewallOptions->getOpt( 'enable_firewall' ) );
999
- $this->resetFirewallProcessor();
1000
  }
1001
-
1002
  protected function handleSubmit_LoginProtect() {
1003
  //Ensures we're actually getting this request from WP.
1004
  check_admin_referer( $this->getSubmenuId('login_protect' ) );
1005
-
1006
- if ( !isset($_POST[self::OptionPrefix.'all_options_input']) ) {
 
 
 
 
 
 
1007
  return;
1008
  }
1009
  $this->loadOptionsHandler( 'LoginProtect' );
1010
- $this->m_oLoginProtectOptions->updatePluginOptionsFromSubmit( $_POST[self::OptionPrefix.'all_options_input'] );
1011
  $this->setSharedOption( 'enable_login_protect', $this->m_oLoginProtectOptions->getOpt( 'enable_login_protect' ) );
1012
- $this->resetLoginProcessor();
 
 
 
 
 
 
 
 
 
 
 
 
 
1013
  }
1014
 
1015
  protected function handleSubmit_CommentsFilter() {
1016
  //Ensures we're actually getting this request from WP.
1017
  check_admin_referer( $this->getSubmenuId('comments_filter' ) );
1018
 
1019
- if ( !isset($_POST[self::OptionPrefix.'all_options_input']) ) {
1020
  return;
1021
  }
1022
  $this->loadOptionsHandler( 'CommentsFilter' );
1023
- $this->m_oCommentsFilterOptions->updatePluginOptionsFromSubmit( $_POST[self::OptionPrefix.'all_options_input'] );
1024
  $this->setSharedOption( 'enable_comments_filter', $this->m_oCommentsFilterOptions->getOpt( 'enable_comments_filter' ) );
1025
- $this->resetCommentsProcessor();
1026
  }
1027
 
1028
  protected function handleSubmit_Lockdown() {
1029
  //Ensures we're actually getting this request from WP.
1030
  check_admin_referer( $this->getSubmenuId('lockdown' ) );
1031
 
1032
- if ( !isset($_POST[self::OptionPrefix.'all_options_input']) ) {
1033
  return;
1034
  }
1035
  $this->loadOptionsHandler( 'Lockdown' );
1036
- $this->m_oLockdownOptions->updatePluginOptionsFromSubmit( $_POST[self::OptionPrefix.'all_options_input'] );
1037
  $this->setSharedOption( 'enable_lockdown', $this->m_oLockdownOptions->getOpt( 'enable_lockdown' ) );
1038
- $this->resetLockdownProcessor();
1039
  }
1040
 
1041
  protected function handleSubmit_AutoUpdates() {
1042
  //Ensures we're actually getting this request from WP.
1043
  check_admin_referer( $this->getSubmenuId( 'autoupdates' ) );
1044
 
1045
- if ( !isset($_POST[self::OptionPrefix.'all_options_input']) ) {
 
 
 
 
 
 
1046
  return;
1047
  }
1048
  $this->loadOptionsHandler( 'AutoUpdates' );
1049
- $this->m_oAutoUpdatesOptions->updatePluginOptionsFromSubmit( $_POST[self::OptionPrefix.'all_options_input'] );
1050
  $this->setSharedOption( 'enable_autoupdates', $this->m_oAutoUpdatesOptions->getOpt( 'enable_autoupdates' ) );
1051
- $this->resetAutoUpdatesProcessor();
1052
  }
1053
 
1054
  protected function handleSubmit_FirewallLog() {
1055
 
1056
  // Ensures we're actually getting this request from a valid WP submission.
1057
- if ( !isset( $_REQUEST['_wpnonce'] ) || !wp_verify_nonce( $_REQUEST['_wpnonce'], $this->getSubmenuId( 'firewall_log' ) ) ) {
 
1058
  wp_die();
1059
  }
 
 
1060
 
1061
  // At the time of writing the page only has 1 form submission item - clear log
1062
- if ( isset( $_POST['clear_log_submit'] ) ) {
1063
  $this->loadProcessor( 'Logging' );
1064
  $this->m_oLoggingProcessor->recreateTable();
1065
  }
1066
- else if ( isset( $_GET['blackip'] ) ) {
1067
- $this->addRawIpsToFirewallList( 'ips_blacklist', array( $_GET['blackip'] ) );
 
 
 
 
1068
  }
1069
- else if ( isset( $_GET['unblackip'] ) ) {
1070
- $this->removeRawIpsFromFirewallList( 'ips_blacklist', array( $_GET['unblackip'] ) );
 
 
 
 
 
 
 
 
1071
  }
1072
- else if ( isset( $_GET['whiteip'] ) ) {
1073
- $this->addRawIpsToFirewallList( 'ips_whitelist', array( $_GET['whiteip'] ) );
 
 
 
 
 
1074
  }
1075
- else if ( isset( $_GET['unwhiteip'] ) ) {
1076
- $this->removeRawIpsFromFirewallList( 'ips_whitelist', array( $_GET['unwhiteip'] ) );
 
 
 
 
1077
  }
1078
- wp_safe_redirect( admin_url( "admin.php?page=".$this->getSubmenuId('firewall_log') ) ); //means no admin message is displayed
1079
  exit();
1080
  }
1081
-
1082
- public function clearCaches() {
1083
- $this->resetFirewallProcessor();
1084
- $this->resetLoginProcessor();
1085
- $this->resetLoggingProcessor();
1086
- $this->resetCommentsProcessor();
1087
- }
1088
-
1089
- protected function resetEmailProcessor() {
1090
- $this->m_oEmailProcessor = false;
1091
- self::deleteOption( 'email_processor' );
1092
- $this->loadProcessor( 'Email' );
1093
- }
1094
-
1095
- protected function resetFirewallProcessor() {
1096
- $this->resetEmailProcessor();
1097
- $this->m_oFirewallProcessor = false;
1098
- self::deleteOption( 'firewall_processor' );
1099
- $this->loadProcessor( 'Firewall' );
1100
- }
1101
-
1102
- protected function resetLoginProcessor() {
1103
- $this->m_oLoginProtectProcessor = false;
1104
- self::deleteOption( 'login_processor' );
1105
- $this->loadProcessor( 'LoginProtect' );
1106
- }
1107
-
1108
- protected function resetCommentsProcessor() {
1109
- $this->m_oCommentsFilterProcessor = false;
1110
- self::deleteOption( 'comments_processor' );
1111
- $this->loadProcessor( 'CommentsFilter' );
1112
- }
1113
-
1114
- protected function resetLockdownProcessor() {
1115
- $this->m_oLockdownProcessor = false;
1116
- self::deleteOption( 'lockdown_processor' );
1117
- $this->loadProcessor( 'Lockdown' );
1118
- }
1119
-
1120
- protected function resetAutoUpdatesProcessor() {
1121
- $this->m_oLockdownProcessor = false;
1122
- self::deleteOption( 'autoupdates_processor' );
1123
- $this->loadProcessor( 'AutoUpdates' );
1124
- }
1125
-
1126
- protected function resetLoggingProcessor() {
1127
- $this->m_oLoggingProcessor = false;
1128
- self::deleteOption( 'logging_processor' );
1129
- $this->loadProcessor( 'Logging' );
1130
- }
1131
-
1132
  protected function importFromFirewall2Plugin() {
1133
  $this->loadOptionsHandler( 'all' );
1134
  require_once( dirname(__FILE__).'/src/icwp-import-wpf2-processor.php' );
1135
- $oImportProcessor = new ICWP_ImportWpf2Processor( $this->m_oWpsfOptions, $this->m_oFirewallOptions );
1136
  $oImportProcessor->runImport();
1137
  }
1138
 
1139
- public function onWpPluginActionLinks( $inaActionLinks, $insFile ) {
1140
-
1141
- if ( $insFile == plugin_basename( __FILE__ ) ) {
1142
- if ( !$this->hasPermissionToSubmit() ) {
1143
- if ( array_key_exists( 'edit', $inaActionLinks ) ) {
1144
- unset( $inaActionLinks['edit'] );
1145
- }
1146
- if ( array_key_exists( 'deactivate', $inaActionLinks ) ) {
1147
- unset( $inaActionLinks['deactivate'] );
1148
- }
1149
- }
1150
- $sSettingsLink = '<a href="'.admin_url( "admin.php" ).'?page='.$this->getSubmenuId().'">' . 'Dashboard' . '</a>';
1151
- array_unshift( $inaActionLinks, $sSettingsLink );
1152
- }
1153
- return $inaActionLinks;
1154
- }
1155
-
1156
  public function onWpPluginsLoaded() {
1157
  parent::onWpPluginsLoaded();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1158
 
1159
  if ( $this->isValidAdminArea()
1160
- && $this->m_oWpsfOptions->getOpt('enable_upgrade_admin_notice') == 'Y'
1161
  && $this->hasPermissionToSubmit()
1162
  ) {
1163
  $this->m_fDoAutoUpdateCheck = true;
1164
  }
1165
-
1166
- $this->load_textdomain();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1167
 
1168
- add_action( 'deactivate_plugin', array( $this, 'preventDeactivation' ), 1, 1 );
1169
- $this->removePluginConflicts(); // removes conflicts with other plugins
 
 
 
1170
  }
1171
-
1172
  /**
1173
- * @param string $insPlugin - the path to the plugin file
1174
  */
1175
- public function preventDeactivation( $insPlugin ) {
1176
- if ( strpos( $insPlugin, basename(__FILE__) ) !== false && !$this->hasPermissionToSubmit() ) {
1177
- wp_die(
1178
- _wpsf__( 'Sorry, you do not have permission to disable this plugin. You need to authenticate first.' )
1179
- );
1180
  }
 
1181
  }
1182
-
1183
- public function onWpShutdown() {
1184
- parent::onWpShutdown();
1185
- $this->saveProcessors_Action();
 
 
 
 
 
 
1186
  }
1187
 
1188
- protected function deleteAllPluginDbOptions() {
1189
-
1190
- parent::deleteAllPluginDbOptions();
1191
- if ( !current_user_can( 'manage_options' ) ) {
1192
- return;
1193
- }
1194
-
1195
- $this->loadProcessor( 'Logging' );
1196
- $this->m_oLoggingProcessor->dropTable();
1197
-
1198
- $this->loadProcessor( 'LoginProtect' );
1199
- $this->m_oLoginProtectProcessor->dropTable();
1200
 
1201
- $this->loadProcessor( 'CommentsFilter' );
1202
- $this->m_oCommentsFilterProcessor->dropTable();
 
 
 
 
 
1203
 
1204
- $aOptions = $this->getAllOptions();
1205
- foreach( $aOptions as &$oOption ) {
1206
- $oOption->deletePluginOptions();
 
 
 
1207
  }
1208
- remove_action( 'shutdown', array( $this, 'onWpShutdown' ) );
1209
  }
1210
 
1211
- public function onWpPluginUpdateMessage() {
1212
- echo '<div style="color: #dd3333;">'
1213
- ._wpsf__( 'Upgrade Now To Keep Your Firewall Up-To-Date With The Latest Features.' )
1214
- . '</div>';
1215
  }
1216
-
1217
- public function onWpDeactivatePlugin() {
1218
- if ( $this->m_oWpsfOptions->getOpt( 'delete_on_deactivate' ) == 'Y' ) {
1219
- $this->deleteAllPluginDbOptions();
1220
- }
1221
  }
1222
 
1223
- public function enqueueBootstrapAdminCss() {
1224
- wp_register_style( 'worpit_bootstrap_wpadmin_css', $this->getCssUrl( 'bootstrap-wpadmin.css' ), false, self::$VERSION );
1225
- wp_enqueue_style( 'worpit_bootstrap_wpadmin_css' );
1226
- wp_register_style( 'worpit_bootstrap_wpadmin_css_fixes', $this->getCssUrl('bootstrap-wpadmin-fixes.css'), array('worpit_bootstrap_wpadmin_css'), self::$VERSION );
1227
- wp_enqueue_style( 'worpit_bootstrap_wpadmin_css_fixes' );
1228
- }
1229
-
1230
- public function addRawIpsToFirewallList( $insListName, $inaNewIps ) {
1231
 
1232
- $this->loadOptionsHandler( 'Firewall' );
1233
-
1234
- $aIplist = $this->m_oFirewallOptions->getOpt( $insListName );
1235
- if ( empty( $aIplist ) ) {
1236
- $aIplist = array();
1237
  }
1238
- $aNewList = array();
1239
- foreach( $inaNewIps as $sAddress ) {
1240
- $aNewList[ $sAddress ] = '';
1241
- }
1242
- $aIplist = $this->m_oFirewallOptions->setOpt( $insListName, ICWP_DataProcessor::Add_New_Raw_Ips( $aIplist, $aNewList ) );
1243
- $this->resetFirewallProcessor();
1244
- }
1245
 
1246
- public function removeRawIpsFromFirewallList( $insListName, $inaRemoveIps ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1247
 
1248
- $this->loadOptionsHandler( 'Firewall' );
1249
-
1250
- $aIplist = $this->m_oFirewallOptions->getOpt( $insListName );
1251
- if ( empty( $aIplist ) || empty( $inaRemoveIps ) ) {
1252
- return;
1253
  }
1254
- $aIplist = $this->m_oFirewallOptions->setOpt( $insListName, ICWP_DataProcessor::Remove_Raw_Ips( $aIplist, $inaRemoveIps ) );
1255
- $this->resetFirewallProcessor();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1256
  }
1257
-
1258
  /**
 
1259
  */
1260
- protected function filterIpLists() {
1261
-
1262
- $nNewAddedCount = 0;
1263
- $mResult = $this->processIpFilter( 'ips_whitelist', 'icwp_simple_firewall_whitelist_ips', $nNewAddedCount );
1264
- if ( $mResult !== false && $nNewAddedCount > 0 ) {
1265
- $this->m_oFirewallOptions->setOpt( 'ips_whitelist', $mResult );
1266
- $this->resetFirewallProcessor();
1267
- }
1268
-
1269
- $nNewAddedCount = 0;
1270
- $mResult = $this->processIpFilter( 'ips_blacklist', 'icwp_simple_firewall_blacklist_ips', $nNewAddedCount );
1271
- if ( $mResult !== false && $nNewAddedCount > 0 ) {
1272
- $this->m_oFirewallOptions->setOpt( 'ips_blacklist', $mResult );
1273
- $this->resetFirewallProcessor();
1274
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1275
  }
1276
 
1277
- /**
1278
- * @param string $insExistingListKey
1279
- * @param string $insFilterName
1280
- * @param integer $outnNewAdded
1281
- * @return array|false
1282
- */
1283
- protected function processIpFilter( $insExistingListKey, $insFilterName, &$outnNewAdded = 0 ) {
1284
-
1285
- $aFilterIps = array();
1286
- $aFilterIps = apply_filters( $insFilterName, $aFilterIps );
1287
-
1288
- if ( !empty( $aFilterIps ) ) {
1289
-
1290
- $aNewIps = array();
1291
- foreach( $aFilterIps as $mKey => $sValue ) {
1292
-
1293
- if ( is_string( $mKey ) ) { //it's the IP
1294
- $sIP = $mKey;
1295
- $sLabel = $sValue;
1296
- }
1297
- else { //it's not an associative array, so the value is the IP
1298
- $sIP = $sValue;
1299
- $sLabel = '';
1300
- }
1301
- $aNewIps[ $sIP ] = $sLabel;
1302
- }
1303
-
1304
- // Get the existing list
1305
- $this->loadOptionsHandler( 'Firewall' );
1306
- $aExistingIpList = $this->m_oFirewallOptions->getOpt( $insExistingListKey );
1307
- if ( !is_array( $aExistingIpList ) ) {
1308
- $aExistingIpList = array();
1309
- }
1310
- return ICWP_DataProcessor::Add_New_Raw_Ips( $aExistingIpList, $aNewIps, $outnNewAdded );
1311
  }
1312
- return false;
1313
  }
1314
 
1315
- private function adminNoticeTranslations() {
1316
-
1317
- $oCurrentUser = wp_get_current_user();
1318
- if ( !($oCurrentUser instanceof WP_User) ) {
1319
- return;
1320
- }
1321
- $nUserId = $oCurrentUser->ID;
1322
-
1323
- $sAlreadyShowTranslationNotice = get_user_meta( $nUserId, self::OptionPrefix.'plugin_translation_notice', true );
1324
- // A guard whereby if we can't ever get a value for this meta, it means we can never set it.
1325
- if ( empty( $sAlreadyShowTranslationNotice ) ) {
1326
- //the value has never been set, or it's been installed for the first time.
1327
- $this->updateTranslationNoticeShownUserMeta( $nUserId, 'M' );
1328
- 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.
1329
- }
1330
-
1331
- if ( $sAlreadyShowTranslationNotice !== 'Y' ) {
1332
-
1333
- $sRedirectPage = isset( $GLOBALS['pagenow'] ) ? $GLOBALS['pagenow'] : 'index.php';
1334
- ob_start();
1335
- ?>
1336
- <style>
1337
- a#fromIcwp { padding: 0 5px; border-bottom: 1px dashed rgba(0,0,0,0.1); color: blue; font-weight: bold; }
1338
- </style>
1339
- <form id="IcwpUpdateNotice" method="post" action="admin.php?page=<?php echo $this->getSubmenuId('firewall'); ?>">
1340
- <input type="hidden" value="<?php echo $sRedirectPage; ?>" name="redirect_page" id="redirect_page">
1341
- <input type="hidden" value="1" name="<?php echo self::OptionPrefix; ?>hide_translation_notice" id="<?php echo self::OptionPrefix; ?>hide_translation_notice">
1342
- <input type="hidden" value="<?php echo $nUserId; ?>" name="user_id" id="user_id">
1343
- <h4 style="margin:10px 0 3px;">
1344
- <?php _wpsf_e( 'Would you like to help translate the WordPress Simple Firewall into your language?' ); ?>
1345
- <?php printf( _wpsf__( 'Head over to: %s' ), '<a href="http://translate.icontrolwp.com" target="_blank">translate.icontrolwp.com</a>' ); ?>
1346
- </h4>
1347
- <input type="submit" value="<?php _wpsf_e( 'Dismiss this notice' ); ?>" name="submit" class="button" style="float:left; margin-bottom:10px;">
1348
- <div style="clear:both;"></div>
1349
- </form>
1350
- <?php
1351
- $sNotice = ob_get_contents();
1352
- ob_end_clean();
1353
- $this->getAdminNotice( $sNotice, 'updated', true );
1354
- }
1355
  }
1356
-
1357
  /**
1358
- * Shows the update notification - will bail out if the current user is not an admin
1359
  */
1360
- private function adminNoticeVersionUpgrade() {
1361
-
1362
- $oCurrentUser = wp_get_current_user();
1363
- if ( !($oCurrentUser instanceof WP_User) ) {
1364
- return;
1365
- }
1366
- $nUserId = $oCurrentUser->ID;
1367
- $sCurrentVersion = get_user_meta( $nUserId, self::OptionPrefix.'current_version', true );
1368
- // A guard whereby if we can't ever get a value for this meta, it means we can never set it.
1369
- // If we can never set it, we shouldn't force the Ads on those users who can't get rid of it.
1370
- if ( empty( $sCurrentVersion ) ) { //the value has never been set, or it's been installed for the first time.
1371
- $this->updateVersionUserMeta( $nUserId );
1372
- 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.
1373
- }
1374
-
1375
- if ( $sCurrentVersion !== self::$VERSION ) {
1376
-
1377
- $sRedirectPage = isset( $GLOBALS['pagenow'] ) ? $GLOBALS['pagenow'] : 'index.php';
1378
- $sRedirectPage = 'admin.php?page=icwp-wpsf';
1379
- ob_start();
1380
- ?>
1381
- <style>
1382
- a#fromIcwp { padding: 0 5px; border-bottom: 1px dashed rgba(0,0,0,0.1); color: blue; font-weight: bold; }
1383
- </style>
1384
- <form id="IcwpUpdateNotice" method="post" action="admin.php?page=<?php echo $this->getSubmenuId('firewall'); ?>">
1385
- <input type="hidden" value="<?php echo $sRedirectPage; ?>" name="redirect_page" id="redirect_page">
1386
- <input type="hidden" value="1" name="<?php echo self::OptionPrefix; ?>hide_update_notice" id="<?php echo self::OptionPrefix; ?>hide_update_notice">
1387
- <input type="hidden" value="<?php echo $nUserId; ?>" name="user_id" id="user_id">
1388
- <h4 style="margin:10px 0 3px;">
1389
- <?php _wpsf_e( 'Note: WordPress Simple Firewall plugin does not automatically turn on when you install/update.' ); ?>
1390
- <?php printf( _wpsf__( 'There may also be %simportant updates to read about%s.' ), '<a href="http://icwp.io/27" id="fromIcwp" title="WordPress Simple Firewall" target="_blank">', '</a>' ); ?>
1391
- </h4>
1392
- <input type="submit" value="Okay, show me the dashboard." name="submit" class="button" style="float:left; margin-bottom:10px;">
1393
- <div style="clear:both;"></div>
1394
- </form>
1395
- <?php
1396
- $sNotice = ob_get_contents();
1397
- ob_end_clean();
1398
- $this->getAdminNotice( $sNotice, 'updated', true );
1399
  }
 
1400
  }
1401
-
1402
- private function adminNoticeOptionsUpdated() {
1403
-
1404
- $sAdminFeedbackNotice = $this->m_oWpsfOptions->getOpt( 'feedback_admin_notice' );
1405
- if ( !empty( $sAdminFeedbackNotice ) ) {
1406
- $sNotice = '<p>'.$sAdminFeedbackNotice.'</p>';
1407
- $this->getAdminNotice( $sNotice, 'updated', true );
1408
- $this->m_oWpsfOptions->setOpt( 'feedback_admin_notice', '' );
1409
- }
1410
  }
1411
  }
1412
 
1413
  endif;
1414
 
1415
- $oICWP_Wpsf = new ICWP_Wordpress_Simple_Firewall();
3
  * Plugin Name: WordPress Simple Firewall
4
  * Plugin URI: http://icwp.io/2f
5
  * Description: A Simple WordPress Firewall
6
+ * Version: 2.6.6
7
  * Text Domain: wp-simple-firewall
8
  * Author: iControlWP
9
  * Author URI: http://icwp.io/2e
10
  */
11
 
12
  /**
13
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
14
  * All rights reserved.
15
  *
16
  * "WordPress Simple Firewall" is
30
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
  */
32
 
33
+ require_once( dirname(__FILE__).'/src/icwp-feature-master.php' );
34
  require_once( dirname(__FILE__).'/src/icwp-data-processor.php' );
35
 
36
  if ( !function_exists( '_wpsf_e' ) ) {
46
 
47
  if ( !class_exists('ICWP_Wordpress_Simple_Firewall') ):
48
 
49
+ class ICWP_Wordpress_Simple_Firewall extends ICWP_Feature_Master {
50
+
51
+ /**
52
+ * Should be updated each new release.
53
+ * @var string
54
+ */
55
+ const PluginVersion = '2.6.6';
56
 
57
+ /**
58
+ * @var string
59
+ */
60
+ const PluginTextDomain = 'wp-simple-firewall';
61
  /**
62
  * Should be updated each new release.
63
  * @var string
64
  */
65
+ const PluginSlug = 'wpsf'; //ALL database options use this as the prefix.
 
66
  /**
67
+ * @var string
68
  */
69
+ const AdminAccessKeyCookieName = 'icwp_wpsf_aakcook';
70
 
71
  /**
72
  * @var ICWP_OptionsHandler_Firewall
77
  * @var ICWP_OptionsHandler_LoginProtect
78
  */
79
  protected $m_oLoginProtectOptions;
80
+ /**
81
+ * @var ICWP_OptionsHandler_PrivacyProtect
82
+ */
83
+ protected $m_oPrivacyProtectOptions;
84
 
85
  /**
86
  * @var ICWP_OptionsHandler_CommentsFilter
96
  * @var ICWP_OptionsHandler_AutoUpdates
97
  */
98
  protected $m_oAutoUpdatesOptions;
99
+
100
+ /**
101
+ * @var ICWP_OptionsHandler_Email_Wpsf
102
+ */
103
+ protected $m_oEmailOptions;
104
 
105
  /**
106
  * @var ICWP_FirewallProcessor
116
  * @var ICWP_CommentsFilterProcessor
117
  */
118
  protected $m_oCommentsFilterProcessor;
119
+
120
  /**
121
  * @var ICWP_LockdownProcessor
122
  */
123
  protected $m_oLockdownProcessor;
124
+ /**
125
+ * @var ICWP_WPSF_PrivacyProtectProcessor
126
+ */
127
+ protected $m_oPrivacyProtectProcessor;
128
 
129
  /**
130
+ * @var ICWP_WPSF_AutoUpdatesProcessor
131
  */
132
  protected $m_oAutoUpdatesProcessor;
133
 
134
  /**
135
+ * @var ICWP_WPSF_LoggingProcessor
136
  */
137
  protected $m_oLoggingProcessor;
138
 
140
  * @var ICWP_EmailProcessor
141
  */
142
  protected $m_oEmailProcessor;
143
+
144
+ /**
145
+ * @var bool
146
+ */
147
+ private $fAdminAccessPermSubmit = null;
148
+
149
+ /**
150
+ */
151
  public function __construct() {
152
 
153
  $this->m_fNetworkAdminOnly = true;
154
+ $this->m_sPluginRootFile = __FILE__; //ensure all relative paths etc. are setup.
155
+
156
+ self::$sOptionPrefix = sprintf( '%s_%s_', self::BaseSlug, self::PluginSlug );
157
+ $this->m_sVersion = self::PluginVersion;
158
+ $this->m_sPluginHumanName = "WordPress Simple Firewall";
159
+ $this->m_sPluginTextDomain = self::PluginTextDomain;
160
+ $this->m_sPluginMenuTitle = "Simple Firewall";
161
+ $this->m_sPluginSlug = self::PluginSlug;
162
+ $this->m_sParentMenuIdSuffix = self::PluginSlug;
163
+
164
+ parent::__construct(
165
+ array(
166
+ 'logging' => 'Logging',
167
+ 'email' => 'Email',
168
+ 'firewall' => 'Firewall',
169
+ 'login_protect' => 'LoginProtect',
170
+ 'comments_filter' => 'CommentsFilter',
171
+ // 'privacy_protect' => 'PrivacyProtect',
172
+ 'lockdown' => 'Lockdown',
173
+ 'autoupdates' => 'AutoUpdates'
174
+ ),
175
+ array(
176
+ 'm_oPluginMainOptions',
177
+ 'm_oEmailOptions',
178
+ 'm_oFirewallOptions',
179
+ 'm_oLoginProtectOptions',
180
+ 'm_oCommentsFilterOptions',
181
+ 'm_oPrivacyProtectOptions',
182
+ 'm_oLockdownOptions',
183
+ 'm_oAutoUpdatesOptions'
184
+ )
185
+ );
186
+
187
  // loads the base plugin options from 1 db call
188
+ $this->loadOptionsHandler( 'PluginMain' );
189
+ $this->m_fAutoPluginUpgrade = false && $this->m_oPluginMainOptions->getOpt( 'enable_auto_plugin_upgrade' ) == 'Y';
190
 
191
  // checks for filesystem based firewall overrides
192
  $this->override();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
  if ( isset( $_GET['turnoffperm'] ) ) {
195
  $this->setPermissionToSubmit( false );
196
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
 
198
+ add_filter( 'pre_update_option', array($this, 'blockOptionsSaves'), 1, 3 );
 
 
 
 
 
 
 
 
 
 
199
  }
200
+
201
  /**
202
+ * @return string
 
 
 
203
  */
204
+ protected function override() {
205
+ $sSetting = parent::override();
206
+ if ( empty( $sSetting ) ) {
207
+ return $sSetting;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
+ $this->m_oPluginMainOptions->setOpt( 'enable_admin_access_restriction', $sSetting );
210
+ $this->m_oPluginMainOptions->savePluginOptions();
211
+ return $sSetting;
212
  }
213
 
214
  /**
215
  * Should be called from the constructor so as to ensure it is called as early as possible.
216
  *
217
+ * @return void
 
218
  */
219
  public function runFirewallProcess() {
220
 
 
 
 
 
221
  $this->loadProcessor( 'Firewall' );
222
  $fFirewallBlockUser = !$this->m_oFirewallProcessor->doFirewallCheck();
223
 
224
  if ( $fFirewallBlockUser ) {
 
225
  if ( $this->m_oFirewallProcessor->getNeedsEmailHandler() ) {
226
  $this->loadProcessor( 'Email' );
227
  $this->m_oFirewallProcessor->setEmailHandler( $this->m_oEmailProcessor );
 
 
 
 
 
228
  }
229
+ $this->m_oFirewallProcessor->doPreFirewallBlock();
230
  }
 
 
231
 
232
  if ( $fFirewallBlockUser ) {
233
+ $this->shutdown();
234
  $this->m_oFirewallProcessor->doFirewallBlock();
235
  }
 
 
236
  }
237
 
238
  /**
240
  */
241
  public function runLoginProtect() {
242
  $this->loadProcessor( 'LoginProtect' );
243
+ $this->loadProcessor( 'Email' );
244
+ $this->m_oLoginProtectProcessor->setEmailHandler( $this->m_oEmailProcessor );
245
  $this->m_oLoginProtectProcessor->run();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  }
247
 
248
  /**
249
+ * Handles the running of all Auto Update processes.
250
  */
251
  public function runAutoUpdates() {
252
  $this->loadProcessor( 'AutoUpdates' );
253
+ $this->m_oAutoUpdatesProcessor->run( $this->getPluginFile() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  }
255
 
256
  protected function createPluginSubMenuItems() {
 
 
 
 
 
257
  $this->m_aPluginMenu = array(
258
  //Menu Page Title => Menu Item name, page ID (slug), callback function for this page - i.e. what to do/load.
259
+ $this->getSubmenuPageTitle( _wpsf__('Firewall') ) => array( 'Firewall', $this->getSubmenuId('firewall'), 'onDisplayAll' ),
260
+ $this->getSubmenuPageTitle( _wpsf__('Login Protect') ) => array( 'Login Protect', $this->getSubmenuId('login_protect'), 'onDisplayAll' ),
261
+ $this->getSubmenuPageTitle( _wpsf__('Comments Filter') ) => array( 'Comments Filter', $this->getSubmenuId('comments_filter'), 'onDisplayAll' ),
262
+ // $this->getSubmenuPageTitle( _wpsf__('Privacy Protect') ) => array( 'Privacy Protect', $this->getSubmenuId('privacy_protect'), 'onDisplayAll' ),
263
+ $this->getSubmenuPageTitle( _wpsf__('Automatic Updates') ) => array( 'Automatic Updates', $this->getSubmenuId('autoupdates'), 'onDisplayAll' ),
264
+ $this->getSubmenuPageTitle( _wpsf__('Lockdown') ) => array( 'Lockdown', $this->getSubmenuId('lockdown'), 'onDisplayAll' ),
265
+ $this->getSubmenuPageTitle( _wpsf__('Firewall Log' ) ) => array( 'Firewall Log', $this->getSubmenuId('firewall_log'), 'onDisplayAll' ),
266
+ // $this->getSubmenuPageTitle( _wpsf__('Privacy Log' ) ) => array( 'Privacy Log', $this->getSubmenuId('privacy_protect_log'), 'onDisplayAll' )
267
  );
268
  }
269
 
270
  protected function handlePluginUpgrade() {
271
  parent::handlePluginUpgrade();
272
 
273
+ $sCurrentPluginVersion = $this->m_oPluginMainOptions->getVersion();
274
 
275
+ if ( $sCurrentPluginVersion !== $this->m_sVersion && current_user_can( 'manage_options' ) ) {
276
 
277
+ $this->loadOptionsHandler( 'all' );
278
+
279
+ // refactoring so that email and logging options are more independent
280
+ if ( version_compare( $sCurrentPluginVersion, '2.3.0', '<' ) ) {
281
+ $this->deleteOption( 'whitelist_admins' );
282
+
283
+ $this->m_oEmailOptions->setOpt( 'block_send_email_address', $this->m_oPluginMainOptions->getOpt( 'block_send_email_address') );
284
+ $this->m_oEmailOptions->setOpt( 'send_email_throttle_limit', $this->m_oPluginMainOptions->getOpt( 'send_email_throttle_limit') );
285
+ }//v2.3.0
286
 
287
  $this->loadProcessor( 'Logging' );
288
  $this->m_oLoggingProcessor->handleInstallUpgrade( $sCurrentPluginVersion );
 
 
 
289
 
290
  // clears all the processor caches
291
  $this->clearCaches();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  }
293
  }
294
 
302
  $this->onDisplayAccessKeyRequest();
303
  return;
304
  }
305
+
306
+ // Just to ensure the nag bar disappears if/when they visit the dashboard
307
+ // regardless of clicking the button.
308
+ $this->updateVersionUserMeta();
309
+
310
+ $sPrefix = str_replace(' ', '-', strtolower($this->m_sPluginMenuTitle) ) .'_page_'.self::BaseSlug.'-'.self::PluginSlug.'-';
311
  $sCurrent = str_replace( $sPrefix, '', current_filter() );
312
+
313
  switch( $sCurrent ) {
314
+ case 'toplevel_page_'.self::BaseSlug.'-'.self::PluginSlug : //special case
315
  $this->onDisplayMainMenu();
316
  break;
317
+ case 'privacy_protect_log' :
318
+ $this->onDisplayPrivacyProtectLog();
319
+ break;
320
  case 'firewall_log' :
321
  $this->onDisplayFirewallLog();
322
  break;
330
  }
331
 
332
  public function onDisplayAccessKeyRequest() {
 
 
 
333
  $aData = array(
 
 
334
  'nonce_field' => $this->getSubmenuId( 'wpsf-access-key' ),
 
335
  );
336
+ $aData = array_merge( $this->getBaseDisplayData(), $aData );
337
  $this->display( 'icwp_wpsf_access_key_request_index', $aData );
338
  }
339
 
340
  public function onDisplayMainMenu() {
341
 
342
+ $this->loadOptionsHandler( 'all', true );
343
+ $aAvailableOptions = array_merge( $this->m_oPluginMainOptions->getOptions(), $this->m_oEmailOptions->getOptions() );
344
+ $sMainOptions = $this->m_oPluginMainOptions->collateAllFormInputsForAllOptions();
345
+ $sEmailMainOptions = $this->m_oEmailOptions->collateAllFormInputsForAllOptions();
346
+ $sAllFormInputOptions = $sMainOptions.(ICWP_OptionsHandler_Base_Wpsf::CollateSeparator).$sEmailMainOptions;
 
 
347
 
348
  $aData = array(
 
 
349
  'aAllOptions' => $aAvailableOptions,
 
350
  'all_options_input' => $sAllFormInputOptions,
 
 
351
  );
352
+ $aData = array_merge( $this->getBaseDisplayData(), $aData );
353
+
354
+ $aData['aMainOptions'] = $this->m_oPluginMainOptions->getPluginOptionsValues();
355
+ $aData['aSummaryData'] = $this->getDashboardSummaryDisplayData();
356
 
 
 
357
  if ( $this->getIsMainFeatureEnabled('firewall') ) {
358
  $this->loadOptionsHandler( 'Firewall' );
359
  $aData['aFirewallOptions'] = $this->m_oFirewallOptions->getPluginOptionsValues();
374
  $this->loadOptionsHandler( 'AutoUpdates' );
375
  $aData['aAutoUpdatesOptions'] = $this->m_oAutoUpdatesOptions->getPluginOptionsValues();
376
  }
 
377
  $this->display( 'icwp_'.$this->m_sParentMenuIdSuffix.'_index', $aData );
378
  }
379
+
380
+ protected function getDashboardSummaryDisplayData() {
381
+
382
+ $aSummaryData = array();
383
+ $aSummaryData[] = array(
384
+ $this->m_oPluginMainOptions->getOpt( 'enable_admin_access_restriction' ) == 'Y',
385
+ _wpsf__('Admin Access Protection'),
386
+ $this->getSubmenuId()
387
+ );
388
+
389
+ $aSummaryData[] = array(
390
+ $this->getIsMainFeatureEnabled('firewall'),
391
+ _wpsf__('Firewall'),
392
+ $this->getSubmenuId( 'firewall' )
393
+ );
394
+
395
+ $aSummaryData[] = array(
396
+ $this->getIsMainFeatureEnabled('login_protect'),
397
+ _wpsf__('Login Protection'),
398
+ $this->getSubmenuId( 'login_protect' )
399
+ );
400
+
401
+ $aSummaryData[] = array(
402
+ $this->getIsMainFeatureEnabled('comments_filter'),
403
+ _wpsf__('Comments Filter'),
404
+ $this->getSubmenuId( 'comments_filter' )
405
+ );
406
+
407
+ $aSummaryData[] = array(
408
+ $this->getIsMainFeatureEnabled('autoupdates'),
409
+ _wpsf__('Auto Updates'),
410
+ $this->getSubmenuId( 'autoupdates' )
411
+ );
412
+
413
+ $aSummaryData[] = array(
414
+ $this->getIsMainFeatureEnabled('lockdown'),
415
+ _wpsf__('Lock Down'),
416
+ $this->getSubmenuId( 'lockdown' )
417
+ );
418
+
419
+ return $aSummaryData;
420
+ }
421
 
422
+ protected function onDisplayPrivacyProtectLog() {
423
+
424
+ $this->loadProcessor( 'PrivacyProtect' );
425
+ $aData = array(
426
+ 'urlrequests_log' => $this->m_oPrivacyProtectProcessor->getLogs( true )
427
+ );
428
+ $aData = array_merge( $this->getBaseDisplayData('privacy_protect_log'), $aData );
429
+ $this->display( 'icwp_wpsf_privacy_protect_log_index', $aData );
430
+ }
431
+
432
  protected function onDisplayFirewallLog() {
433
 
434
  $this->loadOptionsHandler( 'Firewall' );
435
  $aIpWhitelist = $this->m_oFirewallOptions->getOpt( 'ips_whitelist' );
436
  $aIpBlacklist = $this->m_oFirewallOptions->getOpt( 'ips_blacklist' );
 
437
  $this->loadProcessor( 'Logging' );
438
 
439
+ $aLogData = $this->m_oLoggingProcessor->getLogs( true );
440
  $aData = array(
441
+ 'firewall_log' => $aLogData,
 
 
442
  'ip_whitelist' => isset( $aIpWhitelist['ips'] )? $aIpWhitelist['ips'] : array(),
443
  'ip_blacklist' => isset( $aIpBlacklist['ips'] )? $aIpBlacklist['ips'] : array(),
 
 
 
444
  );
445
+ $aData = array_merge( $this->getBaseDisplayData('firewall_log'), $aData );
446
  $this->display( 'icwp_wpsf_firewall_log_index', $aData );
447
  }
448
+
449
  /**
450
  *
451
  * @param ICWP_OptionsHandler_Base_WPSF $inoOptions
452
  * @param string $insSlug
453
  */
454
  protected function onDisplayConfig( $inoOptions, $insSlug ) {
 
455
  $aAvailableOptions = $inoOptions->getOptions();
456
  $sAllFormInputOptions = $inoOptions->collateAllFormInputsForAllOptions();
457
 
458
  $aData = array(
 
 
 
459
  'aAllOptions' => $aAvailableOptions,
460
  'all_options_input' => $sAllFormInputOptions,
 
 
461
  );
462
+ $aData = array_merge( $this->getBaseDisplayData($insSlug), $aData );
463
  $this->display( 'icwp_wpsf_config_'.$insSlug.'_index', $aData );
464
  }
465
+
466
+ /**
467
+ * @return boolean
468
+ */
469
+ protected function isIcwpPluginFormSubmit() {
470
 
471
+ if ( empty($_POST) && empty($_GET) ) {
472
+ return false;
473
+ }
474
+
475
+ $aFormSubmitOptions = array(
476
  'icwp_plugin_form_submit',
477
  'icwp_link_action',
478
  'icwp_wpsf_admin_access_key_request'
479
  );
480
+ foreach( $aFormSubmitOptions as $sOption ) {
481
+ if ( !is_null( $this->fetchRequest( $sOption, false ) ) ) {
 
482
  return true;
483
  }
484
  }
485
+ return false;
486
  }
487
 
488
  protected function handlePluginFormSubmit() {
489
+ if ( !is_null( $this->fetchPost( 'icwp_wpsf_admin_access_key_request' ) ) ) {
 
 
 
 
 
 
490
  return $this->handleSubmit_AccessKeyRequest();
491
  }
492
 
493
+ if ( !$this->hasPermissionToSubmit() || !$this->isIcwpPluginFormSubmit() ) {
494
  return false;
495
  }
496
+
497
+ $sCurrentPage = $this->fetchGet('page');
498
+ if ( !is_null($sCurrentPage) ) {
499
+ switch ( $sCurrentPage ) {
500
  case $this->getSubmenuId():
501
  $this->handleSubmit_Dashboard();
502
  break;
518
  case $this->getSubmenuId( 'firewall_log' ):
519
  $this->handleSubmit_FirewallLog();
520
  break;
521
+ case $this->getSubmenuId( 'privacy_protect' ):
522
+ $this->handleSubmit_PrivacyProtect();
523
+ break;
524
+ case $this->getSubmenuId( 'privacy_protect_log' ):
525
+ $this->handleSubmit_PrivacyProtectLog();
526
+ break;
527
  default:
528
  return false;
529
  break;
530
  }
531
  }
532
+ $this->clearCaches();
533
  return true;
534
  }
535
 
536
  protected function setPermissionToSubmit( $infPermission = false ) {
 
537
  if ( $infPermission ) {
538
+ $this->loadDataProcessor();
539
+ $sValue = md5( $this->m_oPluginMainOptions->getOpt( 'admin_access_key' ).ICWP_WPSF_DataProcessor::GetVisitorIpAddress() );
540
+ $sTimeout = $this->m_oPluginMainOptions->getOpt( 'admin_access_timeout' ) * 60;
541
+ $_COOKIE[ self::AdminAccessKeyCookieName ] = $sValue;
542
  setcookie( self::AdminAccessKeyCookieName, $sValue, time()+$sTimeout, COOKIEPATH, COOKIE_DOMAIN, false );
543
  }
544
  else {
547
  }
548
  }
549
 
 
 
 
 
 
 
 
 
550
  /**
551
  * @return boolean
552
  */
553
  protected function hasPermissionToSubmit() {
554
+
555
+ if ( !is_null( $this->fAdminAccessPermSubmit ) ) {
556
+ return $this->fAdminAccessPermSubmit;
 
557
  }
558
+
559
+ $this->fAdminAccessPermSubmit = true;
560
+ if ( !parent::hasPermissionToSubmit() ) {
561
+ $this->fAdminAccessPermSubmit = false;
562
+ }
563
+ if ( $this->fAdminAccessPermSubmit && $this->m_oPluginMainOptions->getOpt( 'enable_admin_access_restriction' ) == 'Y' ) {
564
+ $sAccessKey = $this->m_oPluginMainOptions->getOpt( 'admin_access_key' );
565
  if ( !empty( $sAccessKey ) ) {
566
+ $this->loadDataProcessor();
567
+ $sHash = md5( $sAccessKey.ICWP_WPSF_DataProcessor::GetVisitorIpAddress() );
568
+ $this->fAdminAccessPermSubmit = isset( $_COOKIE[ self::AdminAccessKeyCookieName ] ) && ( $sHash == $_COOKIE[ self::AdminAccessKeyCookieName ] );
 
 
 
 
 
569
  }
570
  }
571
+ return $this->fAdminAccessPermSubmit;
572
+ }
573
+
574
+ /**
575
+ * Right before a plugin option is due to update it will check that we have permissions to do so and if not, will
576
+ * revert the option to save to the previous one.
577
+ *
578
+ * @param $mValue
579
+ * @param $sOption
580
+ * @param $mOldValue
581
+ * @return mixed
582
+ */
583
+ public function blockOptionsSaves( $mValue, $sOption, $mOldValue ) {
584
+ if ( !preg_match( '/^'.self::$sOptionPrefix.'.*_options$/', $sOption ) || $this->fHasFtpOverride ) {
585
+ return $mValue;
586
+ }
587
+ return $this->hasPermissionToSubmit()? $mValue : $mOldValue;
588
  }
589
 
590
  protected function handleSubmit_AccessKeyRequest() {
591
  //Ensures we're actually getting this request from WP.
592
  check_admin_referer( $this->getSubmenuId('wpsf-access-key') );
593
 
594
+ $this->loadOptionsHandler( 'PluginMain' );
595
+ $sAccessKey = md5( trim( $this->fetchPost( 'icwp_wpsf_admin_access_key_request' ) ) );
596
+ $sStoredAccessKey = $this->m_oPluginMainOptions->getOpt( 'admin_access_key' );
597
 
598
  if ( $sAccessKey === $sStoredAccessKey ) {
599
  $this->setPermissionToSubmit( true );
600
+ header( 'Location: '.network_admin_url('admin.php?page=icwp-wpsf') );
601
  exit();
602
  }
603
  return false;
605
 
606
  protected function handleSubmit_Dashboard() {
607
  //Ensures we're actually getting this request from WP.
608
+ check_admin_referer( $this->getSubmenuId() );
609
 
610
+ $aInputOptions = $this->fetchPost( self::$sOptionPrefix.'all_options_input' );
611
+ if ( is_null( $aInputOptions ) ) {
612
  return false;
613
  }
614
 
615
+ $this->loadOptionsHandler( 'PluginMain' );
616
+ $this->m_oPluginMainOptions->updatePluginOptionsFromSubmit( $aInputOptions );
617
+
618
+ $this->loadOptionsHandler( 'Email' );
619
+ $this->m_oEmailOptions->updatePluginOptionsFromSubmit( $aInputOptions );
620
+
621
+ $this->setSharedOption( 'enable_firewall', $this->m_oPluginMainOptions->getOpt( 'enable_firewall' ) );
622
+ $this->setSharedOption( 'enable_login_protect', $this->m_oPluginMainOptions->getOpt( 'enable_login_protect' ) );
623
+ $this->setSharedOption( 'enable_comments_filter', $this->m_oPluginMainOptions->getOpt( 'enable_comments_filter' ) );
624
+ $this->setSharedOption( 'enable_lockdown', $this->m_oPluginMainOptions->getOpt( 'enable_lockdown' ) );
625
+ $this->setSharedOption( 'enable_autoupdates', $this->m_oPluginMainOptions->getOpt( 'enable_autoupdates' ) );
626
+ $this->setSharedOption( 'enable_privacy_protect', $this->m_oPluginMainOptions->getOpt( 'enable_privacy_protect' ) );
627
+
628
+ $this->saveOptions();
629
  $this->clearCaches();
630
+
631
+ if ( !$this->fetchPost( self::$sOptionPrefix.'enable_admin_access_restriction' ) ) {
632
+ $this->setPermissionToSubmit( false );
633
+ }
634
+ else {
635
+ wp_safe_redirect( network_admin_url('admin.php?page=icwp-wpsf') );
636
+ }
637
  }
638
 
639
  protected function handleSubmit_FirewallConfig() {
643
  if ( isset($_POST[ 'import-wpf2-submit' ] ) ) {
644
  $this->importFromFirewall2Plugin();
645
  }
646
+ else if ( !isset($_POST[self::$sOptionPrefix.'all_options_input']) ) {
647
  return;
648
  }
649
  else {
650
  $this->loadOptionsHandler( 'Firewall' );
651
+ $this->m_oFirewallOptions->updatePluginOptionsFromSubmit( $_POST[self::$sOptionPrefix.'all_options_input'] );
652
  }
653
  $this->setSharedOption( 'enable_firewall', $this->m_oFirewallOptions->getOpt( 'enable_firewall' ) );
654
+ $this->resetProcessor( 'Firewall' );
655
  }
656
+
657
  protected function handleSubmit_LoginProtect() {
658
  //Ensures we're actually getting this request from WP.
659
  check_admin_referer( $this->getSubmenuId('login_protect' ) );
660
+
661
+ if ( $this->fetchPost( 'terminate-all-logins' ) ) {
662
+ $oProc = $this->getProcessorVar('LoginProtect');
663
+ $oProc->doTerminateAllVerifiedLogins();
664
+ return;
665
+ }
666
+
667
+ if ( !isset($_POST[self::$sOptionPrefix.'all_options_input']) ) {
668
  return;
669
  }
670
  $this->loadOptionsHandler( 'LoginProtect' );
671
+ $this->m_oLoginProtectOptions->updatePluginOptionsFromSubmit( $_POST[self::$sOptionPrefix.'all_options_input'] );
672
  $this->setSharedOption( 'enable_login_protect', $this->m_oLoginProtectOptions->getOpt( 'enable_login_protect' ) );
673
+ $this->resetProcessor( 'LoginProtect' );
674
+ }
675
+
676
+ protected function handleSubmit_PrivacyProtect() {
677
+ //Ensures we're actually getting this request from WP.
678
+ check_admin_referer( $this->getSubmenuId('privacy_protect' ) );
679
+
680
+ if ( !isset($_POST[self::$sOptionPrefix.'all_options_input']) ) {
681
+ return;
682
+ }
683
+ $this->loadOptionsHandler( 'PrivacyProtect' );
684
+ $this->m_oPrivacyProtectOptions->updatePluginOptionsFromSubmit( $_POST[self::$sOptionPrefix.'all_options_input'] );
685
+ $this->setSharedOption( 'enable_privacy_protect', $this->m_oPrivacyProtectOptions->getOpt( 'enable_privacy_protect' ) );
686
+ $this->resetProcessor( 'PrivacyProtect' );
687
  }
688
 
689
  protected function handleSubmit_CommentsFilter() {
690
  //Ensures we're actually getting this request from WP.
691
  check_admin_referer( $this->getSubmenuId('comments_filter' ) );
692
 
693
+ if ( !isset($_POST[self::$sOptionPrefix.'all_options_input']) ) {
694
  return;
695
  }
696
  $this->loadOptionsHandler( 'CommentsFilter' );
697
+ $this->m_oCommentsFilterOptions->updatePluginOptionsFromSubmit( $_POST[self::$sOptionPrefix.'all_options_input'] );
698
  $this->setSharedOption( 'enable_comments_filter', $this->m_oCommentsFilterOptions->getOpt( 'enable_comments_filter' ) );
699
+ $this->resetProcessor( 'CommentsFilter' );
700
  }
701
 
702
  protected function handleSubmit_Lockdown() {
703
  //Ensures we're actually getting this request from WP.
704
  check_admin_referer( $this->getSubmenuId('lockdown' ) );
705
 
706
+ if ( !isset($_POST[self::$sOptionPrefix.'all_options_input']) ) {
707
  return;
708
  }
709
  $this->loadOptionsHandler( 'Lockdown' );
710
+ $this->m_oLockdownOptions->updatePluginOptionsFromSubmit( $_POST[self::$sOptionPrefix.'all_options_input'] );
711
  $this->setSharedOption( 'enable_lockdown', $this->m_oLockdownOptions->getOpt( 'enable_lockdown' ) );
712
+ $this->resetProcessor( 'Lockdown' );
713
  }
714
 
715
  protected function handleSubmit_AutoUpdates() {
716
  //Ensures we're actually getting this request from WP.
717
  check_admin_referer( $this->getSubmenuId( 'autoupdates' ) );
718
 
719
+ if ( isset( $_GET['force_run_auto_updates'] ) && $_GET['force_run_auto_updates'] == 'now' ) {
720
+ $this->loadProcessor( 'AutoUpdates' );
721
+ $this->m_oAutoUpdatesProcessor->setForceRunAutoUpdates( true );
722
+ return;
723
+ }
724
+
725
+ if ( !isset($_POST[self::$sOptionPrefix.'all_options_input']) ) {
726
  return;
727
  }
728
  $this->loadOptionsHandler( 'AutoUpdates' );
729
+ $this->m_oAutoUpdatesOptions->updatePluginOptionsFromSubmit( $_POST[self::$sOptionPrefix.'all_options_input'] );
730
  $this->setSharedOption( 'enable_autoupdates', $this->m_oAutoUpdatesOptions->getOpt( 'enable_autoupdates' ) );
731
+ $this->resetProcessor( 'AutoUpdates' );
732
  }
733
 
734
  protected function handleSubmit_FirewallLog() {
735
 
736
  // Ensures we're actually getting this request from a valid WP submission.
737
+ $sNonce = $this->fetchRequest( '_wpnonce', false );
738
+ if ( is_null( $sNonce ) || !wp_verify_nonce( $sNonce, $this->getSubmenuId( 'firewall_log' ) ) ) {
739
  wp_die();
740
  }
741
+
742
+ $this->loadOptionsHandler( 'Firewall' );
743
 
744
  // At the time of writing the page only has 1 form submission item - clear log
745
+ if ( !is_null( $this->fetchPost( 'clear_log_submit' ) ) ) {
746
  $this->loadProcessor( 'Logging' );
747
  $this->m_oLoggingProcessor->recreateTable();
748
  }
749
+ else {
750
+ $this->m_oFirewallOptions->addRawIpsToFirewallList( 'ips_whitelist', array( $this->fetchGet( 'whiteip' ) ) );
751
+ $this->m_oFirewallOptions->removeRawIpsFromFirewallList( 'ips_whitelist', array( $this->fetchGet( 'unwhiteip' ) ) );
752
+ $this->m_oFirewallOptions->addRawIpsToFirewallList( 'ips_blacklist', array( $this->fetchGet( 'blackip' ) ) );
753
+ $this->m_oFirewallOptions->removeRawIpsFromFirewallList( 'ips_blacklist', array( $this->fetchGet( 'unblackip' ) ) );
754
+ $this->resetProcessor( 'Firewall' );
755
  }
756
+ wp_safe_redirect( network_admin_url( "admin.php?page=".$this->getSubmenuId('firewall_log') ) ); //means no admin message is displayed
757
+ exit();
758
+ }
759
+
760
+ protected function handleSubmit_PrivacyProtectLog() {
761
+
762
+ // Ensures we're actually getting this request from a valid WP submission.
763
+ $sNonce = $this->fetchRequest( '_wpnonce', false );
764
+ if ( is_null( $sNonce ) || !wp_verify_nonce( $sNonce, $this->getSubmenuId( 'privacy_protect_log' ) ) ) {
765
+ wp_die();
766
  }
767
+
768
+ $this->loadOptionsHandler( 'PrivacyProtect' );
769
+
770
+ // At the time of writing the page only has 1 form submission item - clear log
771
+ if ( !is_null( $this->fetchPost( 'clear_log_submit' ) ) ) {
772
+ $this->loadProcessor( 'PrivacyProtect' );
773
+ $this->m_oPrivacyProtectProcessor->recreateTable();
774
  }
775
+ else {
776
+ // $this->m_oFirewallOptions->addRawIpsToFirewallList( 'ips_whitelist', array( $this->fetchGet( 'whiteip' ) ) );
777
+ // $this->m_oFirewallOptions->removeRawIpsFromFirewallList( 'ips_whitelist', array( $this->fetchGet( 'unwhiteip' ) ) );
778
+ // $this->m_oFirewallOptions->addRawIpsToFirewallList( 'ips_blacklist', array( $this->fetchGet( 'blackip' ) ) );
779
+ // $this->m_oFirewallOptions->removeRawIpsFromFirewallList( 'ips_blacklist', array( $this->fetchGet( 'unblackip' ) ) );
780
+ // $this->resetProcessor( 'Firewall' );
781
  }
782
+ wp_safe_redirect( network_admin_url( "admin.php?page=".$this->getSubmenuId('privacy_protect_log') ) ); //means no admin message is displayed
783
  exit();
784
  }
785
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
786
  protected function importFromFirewall2Plugin() {
787
  $this->loadOptionsHandler( 'all' );
788
  require_once( dirname(__FILE__).'/src/icwp-import-wpf2-processor.php' );
789
+ $oImportProcessor = new ICWP_ImportWpf2Processor( $this->m_oPluginMainOptions, $this->m_oFirewallOptions );
790
  $oImportProcessor->runImport();
791
  }
792
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
793
  public function onWpPluginsLoaded() {
794
  parent::onWpPluginsLoaded();
795
+
796
+ $aFeatures = $this->getFeaturesMap();
797
+ foreach( $aFeatures as $sFeatureSlug => $sProcessor ) {
798
+ if ( !$this->getIsMainFeatureEnabled( $sFeatureSlug ) ) {
799
+ continue;
800
+ }
801
+ if ( $sFeatureSlug == 'firewall' ) {
802
+ $this->runFirewallProcess();
803
+ }
804
+ else if ( $sFeatureSlug == 'login_protect' ) {
805
+ $this->runLoginProtect();
806
+ }
807
+ else if ( $sFeatureSlug == 'autoupdates' ) {
808
+ $this->runAutoUpdates();
809
+ }
810
+ else {
811
+ $sProcessorVariable = $this->loadProcessor( $sProcessor );
812
+ $sProcessorVariable->run();
813
+ }
814
+ }
815
 
816
  if ( $this->isValidAdminArea()
817
+ && $this->m_oPluginMainOptions->getOpt('enable_upgrade_admin_notice') == 'Y'
818
  && $this->hasPermissionToSubmit()
819
  ) {
820
  $this->m_fDoAutoUpdateCheck = true;
821
  }
822
+ }
823
+
824
+ public function onWpAdminInit() {
825
+ parent::onWpAdminInit();
826
+
827
+ if ( $this->isValidAdminArea() ) {
828
+ //Someone clicked the button to acknowledge the update
829
+ $sMetaFlag = self::$sOptionPrefix.'hide_update_notice';
830
+ if ( $this->fetchRequest( $sMetaFlag ) == 1 ) {
831
+ $this->updateVersionUserMeta();
832
+ if ( $this->isShowMarketing() ) {
833
+ wp_redirect( network_admin_url( "admin.php?page=".$this->getFullParentMenuId() ) );
834
+ }
835
+ else {
836
+ wp_redirect( network_admin_url( $_POST['redirect_page'] ) );
837
+ }
838
+ }
839
+
840
+ $sMetaFlag = self::$sOptionPrefix.'hide_translation_notice';
841
+ if ( $this->fetchRequest( $sMetaFlag ) == 1 ) {
842
+ $this->updateTranslationNoticeShownUserMeta();
843
+ wp_redirect( network_admin_url( $_POST['redirect_page'] ) );
844
+ }
845
 
846
+ $sMetaFlag = self::$sOptionPrefix.'hide_mailing_list_signup';
847
+ if ( $this->fetchRequest( $sMetaFlag ) == 1 ) {
848
+ $this->updateMailingListSignupShownUserMeta();
849
+ }
850
+ }
851
  }
852
+
853
  /**
854
+ * @return bool
855
  */
856
+ protected function isShowMarketing() {
857
+ // don't show marketing on the first 24hrs.
858
+ if ( $this->getInstallationDays() < 1 ) {
859
+ return false;
 
860
  }
861
+ return parent::isShowMarketing();
862
  }
863
+
864
+ /**
865
+ * Lets you remove certain plugin conflicts that might interfere with this plugin
866
+ *
867
+ * @see ICWP_Pure_Base_V1::removePluginConflicts()
868
+ */
869
+ protected function removePluginConflicts() {
870
+ if ( class_exists('AIO_WP_Security') && isset( $GLOBALS['aio_wp_security'] ) ) {
871
+ remove_action( 'init', array( $GLOBALS['aio_wp_security'], 'wp_security_plugin_init'), 0 );
872
+ }
873
  }
874
 
875
+ /**
876
+ * Updates the current log data with new data.
877
+ *
878
+ * @return void
879
+ */
880
+ protected function updateLogStore() {
 
 
 
 
 
 
881
 
882
+ if ( isset( $this->m_oFirewallProcessor ) && is_object( $this->m_oFirewallProcessor ) && $this->getIsMainFeatureEnabled( 'firewall' ) ) {
883
+ $aLogData = $this->m_oFirewallProcessor->flushLogData();
884
+ if ( !is_null( $aLogData ) && !empty( $aLogData ) ) {
885
+ $this->loadProcessor( 'Logging' );
886
+ $this->m_oLoggingProcessor->addDataToWrite( $aLogData );
887
+ }
888
+ }
889
 
890
+ if ( isset( $this->m_oLoginProtectProcessor ) && is_object( $this->m_oLoginProtectProcessor ) && $this->getIsMainFeatureEnabled( 'login_protect' ) ) {
891
+ $aLogData = $this->m_oLoginProtectProcessor->flushLogData();
892
+ if ( !is_null( $aLogData ) && !empty( $aLogData ) ) {
893
+ $this->loadProcessor( 'Logging' );
894
+ $this->m_oLoggingProcessor->addDataToWrite( $aLogData );
895
+ }
896
  }
 
897
  }
898
 
899
+ protected function shutdown() {
900
+ $this->updateLogStore();
901
+ parent::shutdown();
 
902
  }
903
+
904
+ protected function getPluginsListUpdateMessage() {
905
+ return _wpsf__( 'Upgrade Now To Keep Your Firewall Up-To-Date With The Latest Features.' );
 
 
906
  }
907
 
908
+ protected function getAdminNoticeHtml_Translations() {
 
 
 
 
 
 
 
909
 
910
+ if ( $this->getInstallationDays() < 7 ) {
911
+ return '';
 
 
 
912
  }
 
 
 
 
 
 
 
913
 
914
+ $sMetaFlag = self::$sOptionPrefix.'hide_translation_notice';
915
+
916
+ $sRedirectPage = 'index.php';
917
+ ob_start(); ?>
918
+ <style>
919
+ a#fromIcwp { padding: 0 5px; border-bottom: 1px dashed rgba(0,0,0,0.1); color: blue; font-weight: bold; }
920
+ </style>
921
+ <form id="IcwpTranslationsNotice" method="post" action="admin.php?page=<?php echo $this->getSubmenuId('firewall'); ?>&<?php echo $sMetaFlag; ?>=1">
922
+ <input type="hidden" value="<?php echo $sRedirectPage; ?>" name="redirect_page" id="redirect_page">
923
+ <input type="hidden" value="1" name="<?php echo $sMetaFlag; ?>" id="<?php echo $sMetaFlag; ?>">
924
+ <h4 style="margin:10px 0 3px;">
925
+ <?php _wpsf_e( 'Would you like to help translate the WordPress Simple Firewall into your language?' ); ?>
926
+ <?php printf( _wpsf__( 'Head over to: %s' ), '<a href="http://translate.icontrolwp.com" target="_blank">translate.icontrolwp.com</a>' ); ?>
927
+ </h4>
928
+ <input type="submit" value="<?php _wpsf_e( 'Dismiss this notice' ); ?>" name="submit" class="button" style="float:left; margin-bottom:10px;">
929
+ <div style="clear:both;"></div>
930
+ </form>
931
+ <?php
932
+ $sNotice = ob_get_contents();
933
+ ob_end_clean();
934
+ return $sNotice;
935
+ }
936
+
937
+ protected function getAdminNoticeHtml_VersionUpgrade() {
938
 
939
+ // for now just showing this for the first 3 days of installation.
940
+ if ( $this->getInstallationDays() > 7 ) {
941
+ return '';
 
 
942
  }
943
+
944
+ $sMetaFlag = self::$sOptionPrefix.'hide_update_notice';
945
+
946
+ $sRedirectPage = 'admin.php?page=icwp-wpsf';
947
+ ob_start(); ?>
948
+ <style>a#fromIcwp { padding: 0 5px; border-bottom: 1px dashed rgba(0,0,0,0.1); color: blue; font-weight: bold; }</style>
949
+ <form id="IcwpUpdateNotice" method="post" action="admin.php?page=<?php echo $this->getSubmenuId('firewall'); ?>&<?php echo $sMetaFlag; ?>=1">
950
+ <input type="hidden" value="<?php echo $sRedirectPage; ?>" name="redirect_page" id="redirect_page">
951
+ <input type="hidden" value="1" name="<?php echo $sMetaFlag; ?>" id="<?php echo $sMetaFlag; ?>">
952
+ <p>
953
+ <?php _wpsf_e( 'Note: WordPress Simple Firewall plugin does not automatically turn on when you install/update.' ); ?>
954
+ <?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>' ); ?>
955
+ </p>
956
+ </h4>
957
+ <input type="submit" value="<?php _wpsf_e( 'Okay, show me the dashboard' ); ?>" name="submit" class="button" style="float:left; margin-bottom:10px;">
958
+ <div style="clear:both;"></div>
959
+ </form>
960
+ <?php
961
+ $sNotice = ob_get_contents();
962
+ ob_end_clean();
963
+ return $sNotice;
964
  }
965
+
966
  /**
967
+ * @return string|void
968
  */
969
+ protected function getAdminNoticeHtml_MailingListSignup() {
970
+
971
+ $nDays = $this->getInstallationDays();
972
+ if ( $nDays < 2 ) {
973
+ return '';
 
 
 
 
 
 
 
 
 
974
  }
975
+ $sMetaFlag = self::$sOptionPrefix.'hide_mailing_list_signup';
976
+
977
+ ob_start(); ?>
978
+ <!-- Begin MailChimp Signup Form -->
979
+ <div id="mc_embed_signup">
980
+ <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>
981
+ <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>
982
+ <input type="text" value="" name="EMAIL" class="required email" id="mce-EMAIL" placeholder="Your Email" />
983
+ <input type="text" value="" name="FNAME" class="" id="mce-FNAME" placeholder="Your Name" />
984
+ <input type="hidden" value="<?php echo $nDays; ?>" name="DAYS" class="" id="mce-DAYS" />
985
+ <input type="submit" value="Get The News" name="subscribe" id="mc-embedded-subscribe" class="button" />
986
+ <a href="<?php echo network_admin_url('admin.php?page=icwp-wpsf').'&'.$sMetaFlag.'=1';?>">Dismiss</a>
987
+ <div id="mce-responses" class="clear">
988
+ <div class="response" id="mce-error-response" style="display:none"></div>
989
+ <div class="response" id="mce-success-response" style="display:none"></div>
990
+ </div> <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
991
+ <div style="position: absolute; left: -5000px;"><input type="text" name="b_e736870223389e44fb8915c9a_0e1d527259" tabindex="-1" value=""></div>
992
+ <div class="clear"></div>
993
+ </form>
994
+ </div>
995
+
996
+ <!--End mc_embed_signup-->
997
+ <?php
998
+ $sNotice = ob_get_contents();
999
+ ob_end_clean();
1000
+ return $sNotice;
1001
  }
1002
 
1003
+ protected function getAdminNoticeHtml_OptionsUpdated() {
1004
+ $sAdminFeedbackNotice = $this->m_oPluginMainOptions->getOpt( 'feedback_admin_notice' );
1005
+ if ( !empty( $sAdminFeedbackNotice ) ) {
1006
+ $sNotice = '<p>'.$sAdminFeedbackNotice.'</p>';
1007
+ return $sNotice;
1008
+ $this->m_oPluginMainOptions->setOpt( 'feedback_admin_notice', '' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1009
  }
 
1010
  }
1011
 
1012
+ /**
1013
+ *
1014
+ */
1015
+ protected function getShowAdminNotices() {
1016
+ return $this->m_oPluginMainOptions->getOpt('enable_upgrade_admin_notice') == 'Y';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1017
  }
1018
+
1019
  /**
1020
+ * @return int
1021
  */
1022
+ protected function getInstallationDays() {
1023
+ $this->loadOptionsHandler( 'PluginMain' );
1024
+ $nTimeInstalled = $this->m_oPluginMainOptions->getOpt( 'installation_time' );
1025
+ if ( empty($nTimeInstalled) ) {
1026
+ return 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1027
  }
1028
+ return round( ( time() - $nTimeInstalled ) / DAY_IN_SECONDS );
1029
  }
1030
+
1031
+ protected function getAdminBarNodes() {
1032
+ return array(); //disabled for now
1033
+ $aMenu = array(
1034
+ 'id' => self::$sOptionPrefix.'admin_menu',
1035
+ 'title' => '<span class="pluginlogo_16">&nbsp;</span>'._wpsf__('Firewall').'',
1036
+ 'href' => 'bob',
1037
+ );
1038
+ return array( $aMenu );
1039
  }
1040
  }
1041
 
1042
  endif;
1043
 
1044
+ $oICWP_Wpsf = ICWP_Wordpress_Simple_Firewall::GetInstance( 'ICWP_Wordpress_Simple_Firewall' );
languages/wp-simple-firewall-ca_ES.mo ADDED
Binary file
languages/wp-simple-firewall-es_ES.mo ADDED
Binary file
languages/wp-simple-firewall-fa_IR.mo ADDED
Binary file
languages/wp-simple-firewall-he_IL.mo ADDED
Binary file
languages/wp-simple-firewall-it_IT.mo ADDED
Binary file
languages/wp-simple-firewall-pt_BR.mo ADDED
Binary file
languages/wp-simple-firewall-tr_TR.mo ADDED
Binary file
readme.txt CHANGED
@@ -3,47 +3,38 @@ 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
7
  Requires at least: 3.2.0
8
- Tested up to: 3.7
9
- Stable tag: 2.0.0
10
 
11
- Complete and Simple WordPress Security. Unrestricted, with no premium features.
12
 
13
  == Description ==
14
 
15
- The WordPress Simple Firewall is the only WordPress security plugin that *protects itself* - this plugin
16
- will prevent access to itself so that unauthorized users can't deactivate or screw with your security settings.
17
 
18
- A basic intro to all the features:
 
19
 
20
- [youtube http://www.youtube.com/watch?v=r307fu3Eqbo]
21
-
22
- Protects your WordPress site in 5 main ways:
23
-
24
- = Plugin Self-Protection =
25
-
26
- This plugins locks itself down - you can add access restriction to the plugin itself!
27
-
28
- = A Simple, Effective Firewall =
29
-
30
- Builds upon the simplicity and effectiveness of the WordPress Firewall 2 plugin.
31
 
32
- = WordPress Login Protection =
 
33
 
34
- Adds several layers of protection to the WordPress login screen through identity verification and Brute Force Login hacking prevention.
 
35
 
36
- = Comments and SPAM Protection =
 
37
 
38
- Uses and builds upon tried and tested SPAM prevention and filtering techniques with some unique approaches found only in this plugin.
 
39
 
40
- = WordPress Lockdown =
41
-
42
- Provides options for locking down your WordPress site from both legitimate users and people who may have gained unauthorized access.
43
-
44
- Read more on each section below...
45
 
46
- = A Simple Firewall =
47
 
48
  The WordPress Simple Firewall is built to be reliable, and easy to use by **anyone**. Seriously, the interface is simple! :)
49
 
@@ -145,6 +136,8 @@ A new menu item will appear on the left-hand side called 'Simple Firewall'.
145
 
146
  == Frequently Asked Questions ==
147
 
 
 
148
  = My server has a firewall, why do I need this plugin? =
149
 
150
  This plugin is more of an application firewall, rather than a server/network firewall. It is designed to interpret web calls to your site to
@@ -223,16 +216,200 @@ This is best described on the blog: http://icwp.io/2u
223
 
224
  Best described here: http://icwp.io/2v
225
 
 
 
 
 
 
226
  == Screenshots ==
227
 
228
  == Changelog ==
229
 
230
  = TODO =
231
 
232
- * ADD: Add various WordPress security features dynamically that would otherwise require wp-config.php editing.
233
  * CHANGE: Interface to give a better "At-A-Glance" Dashboard summary view, that also allows you to turn on/off core features.
234
 
235
- = 2.0.0 =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
 
237
  * ADDED: Localization capabilities. All we need now are translators! [Go here to get started](http://translate.icontrolwp.com/).
238
  * ADDED: Option to mask the WordPress version so the real version is never publicly visible.
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: 2.6.6
10
 
11
+ Complete and Simple WordPress Security. Unrestricted, Easy, No Premium Features.
12
 
13
  == Description ==
14
 
15
+ The WordPress Simple Firewall is [all you need to secure your WordPress](http://icwp.io/wpsf09) sites in 6 Key Areas:
 
16
 
17
+ = Plugin Admin Access Protection =
18
+ The **only** WordPress security plugin with a WordPress-independent security key to protects itself. [more info](http://icwp.io/wpsf05)
19
 
20
+ = Firewall Protection =
21
+ Blocks all web requests to the site that violate the firewall rules with easy setup! [more info](http://icwp.io/wpsf06)
 
 
 
 
 
 
 
 
 
22
 
23
+ = Brute Force Login Protection and Two-Factor Authentication =
24
+ Provides highly effective Brute Force Hacking Protection and email based Two-Factor Authenticated login. [more info](http://icwp.io/wpsf07)
25
 
26
+ = Comment SPAM (Full replacement and upgrade from Akismet) =
27
+ Blocks **ALL** automatic Bot-SPAM, and catches Human Comments SPAM without sending data to 3rd parties or charging subscription fees. [more info](http://icwp.io/wpsf08)
28
 
29
+ = WordPress Lock Down =
30
+ Numerous mechanisms to lock down your WordPress admin area, such as blocking file edits and enforcing SSL.
31
 
32
+ = Automatic Updates =
33
+ Take back control of your WordPress Automatic Updates.
34
 
35
+ [youtube http://www.youtube.com/watch?v=r307fu3Eqbo]
 
 
 
 
36
 
37
+ = A Simple Firewall Explained =
38
 
39
  The WordPress Simple Firewall is built to be reliable, and easy to use by **anyone**. Seriously, the interface is simple! :)
40
 
136
 
137
  == Frequently Asked Questions ==
138
 
139
+ Please see the new [help centre](http://icwp.io/firewallhelp) for details on features and some FAQs.
140
+
141
  = My server has a firewall, why do I need this plugin? =
142
 
143
  This plugin is more of an application firewall, rather than a server/network firewall. It is designed to interpret web calls to your site to
216
 
217
  Best described here: http://icwp.io/2v
218
 
219
+ = I'm getting an update message although I have auto update enabled? =
220
+
221
+ The Automatic (Background) WordPress updates happens on a WordPress schedule - it doesn't happen immediately when an update is detected.
222
+ You can either manually upgrade, or WordPress will handle it in due course.
223
+
224
  == Screenshots ==
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
+ = 2.6.6 =
233
+
234
+ * FIX: Improved compatibility with bbPress.
235
+
236
+ = 2.6.5 =
237
+
238
+ * FIX: Could not enable Admin Access Protection feature on new installs due to too aggressive testing on security.
239
+
240
+ = 2.6.4 =
241
+
242
+ * ENHANCED: Dashboard now shows a more visual summary of settings and removes duplicate options settings with links to sections.
243
+ * ENHANCED: WordPress Lock Down options now also set the corresponding WordPress defines if they're not already.
244
+
245
+ = 2.6.3 =
246
+
247
+ * ADDED: More in-line plugin links to help/blog resources
248
+ * ENHANCED: [Admin Access Protection](http://icwp.io/5b) is further enhanced in 3 ways:
249
+
250
+ 1. More robust cookie values using MD5s
251
+ 1. Blocks plugin options updating right at the point of WordPress options update so nothing can rewrite the actual plugin options.
252
+ 1. Locks the current Admin Access session to your IP address - effectively only 1 Simple Firewall admin allowed at a time.
253
+
254
+ = 2.6.2 =
255
+
256
+ * ENHANCED: Added option to completely reject a SPAM comment and redirect to the home page (so it doesn't fill up your database with rubbish)
257
+ * ADDED: Plugin now has an internal stats counter for spam and other significant plugin events.
258
+
259
+ = 2.6.1 =
260
+
261
+ * ADDED: Plugin now installs with default SPAM blacklist.
262
+ * ADDED: Now automatically checks and updates the SPAM blacklist when it's older than 48hrs.
263
+ * ENHANCED: Comment messages indicate where the SPAM content was found when marking human-based spam messages.
264
+
265
+ = 2.6.0 =
266
+
267
+ **Major Features Release: Please review SPAM comments filtering options to determine where SPAM goes**
268
+
269
+ * FEATURE: Added Human SPAM comments filtering - replacement for Akismet that doesn't use or send any data to 3rd party services. Uses [Blacklist provided and maintained by Grant Hutchinson](https://github.com/splorp/wordpress-comment-blacklist)
270
+ * ENHANCED: Two-Factor Login now automatically logs in the user to the admin area without them having to re-login again.
271
+ * ENHANCED: Added ability to terminate all currently (two-factor) verified logins.
272
+ * ENHANCED: Spam filter/scanning adds an explanation to the SPAM content to show why a message was filtered.
273
+ * FIXES: For PHP warnings while in php strict mode.
274
+ * CLEAN: Much cleaning up of code.
275
+
276
+ = 2.5.9 =
277
+
278
+ * FEATURE: Added option to try and exclude search engine bots from firewall checking option - OFF by default.
279
+
280
+ = 2.5.8 =
281
+
282
+ * FEATURE: Added 'PHP Code' Firewall checking option.
283
+
284
+ = 2.5.7 =
285
+
286
+ * IMPROVED: Handling and logic of two-factor authentication and user roles/levels
287
+
288
+ = 2.5.6 =
289
+
290
+ * FEATURE: Added ability to specify the particular WordPress user roles that are subject to 2-factor authentication. (Default: Contributors, Authors, Editors and Administrators)
291
+
292
+ = 2.5.5 =
293
+
294
+ * FEATURE: Added 'Lockdown' feature to force login to WordPress over SSL.
295
+ * FEATURE: Added 'Lockdown' feature to force WordPress Admin dashboard to be delivered over SSL.
296
+ * FIX: Admin restricted access feature wasn't disabled with the "forceOff" option.
297
+
298
+ = 2.5.4 =
299
+
300
+ * FIX: How WordPress Automatic/Background Updates filters worked was changed with WordPress 3.8.2.
301
+
302
+ = 2.5.3 =
303
+
304
+ * UPDATED: Translations. And confirmed compatibility with WordPress 3.9
305
+
306
+ = 2.5.2 =
307
+
308
+ * FEATURE: Option to Prevent Remote Posting to the WordPress Login system. Will check that the login form was submitted from the same site.
309
+
310
+ = 2.5.1 =
311
+
312
+ * UPDATED: Translations and added some partials (Catalan, Persian)
313
+ * FIX: for cleanup cron running on non-existent tables.
314
+
315
+ = 2.5.0 =
316
+
317
+ * FEATURE: Two-Factor Authenticated Login using [Yubikey](http://icwp.io/4i) One Time Passwords (OTP).
318
+
319
+ = 2.4.3 =
320
+
321
+ * ADDED: Translations: Spanish, Italian, Turkish. (~15% complete)
322
+ * UPDATED: Hebrew Translations (100%)
323
+
324
+ = 2.4.2 =
325
+
326
+ * ADDED: Contextual help links for many options. More to come...
327
+ * ADDED: More Portuguese (Brazil) translations (~80%)
328
+
329
+ = 2.4.1 =
330
+
331
+ * ADDED: More strings to the translation set for better multilingual support
332
+ * ADDED: Portuguese (Brazil) translations (~40%)
333
+ * UPDATED: Hebrew Translations
334
+ * FIXED: Automatic cleaning of database logs wasn't actually working as expected. Should now be fixed.
335
+
336
+ = 2.4.0 =
337
+
338
+ * NEW: Option to enable Two-Factor Authentication based on Cookie. In this way you can tie a user session to a single browser.
339
+ * FIX: Better WordPress Multisite (WPMS) Support.
340
+
341
+ = 2.3.4 =
342
+
343
+ * FIX: Automatic updating of itself.
344
+
345
+ = 2.3.3 =
346
+
347
+ * ADDED: Hebrew Translations. Thanks [Ahrale](http://atar4u.com)!
348
+ * ADDED: Automatic trimming of the Firewall access log to 7 days - it just grows too large otherwise.
349
+ * FIX: The previously added automatic clean up of old comments and login protect database entries was wiping out the valid login protect
350
+ entries and was forcing users to re-login every 24hrs.
351
+ * FIX: Some small bugs, errors, and PHPDoc Comments.
352
+
353
+ = 2.3.2 =
354
+
355
+ * ADDED: Automatic cleaning of GASP Comments Filter and Login Protection database entries (older than 24hrs) using WordPress Cron (everyday @ 6am)
356
+ * CHANGED: Huge code refactoring to allow for more easily use with other WordPress plugins.
357
+
358
+ = 2.2.5 =
359
+
360
+ * ADDED: Email sending options for automatic update notifications - options to change the notification email address, or turn it off completely.
361
+
362
+ = 2.2.4 =
363
+
364
+ * FIX: Small bug fix.
365
+ * CHANGED: When running a force automatic updates process, tries to remove influence from other plugins and uses only this plugin's automatic updates settings.
366
+ * CHANGED: A bit of automatic updates code refactoring.
367
+
368
+ = 2.2.2 =
369
+
370
+ * CHANGED: Changed all options to be disabled by default.
371
+ * CHANGED: The option for admin notices will turn off all main admin notices except after you update options.
372
+
373
+ = 2.2.1 =
374
+
375
+ * ADDED: Verified compatibility with WordPress 3.8
376
+
377
+ = 2.2.0 =
378
+
379
+ * CHANGED: Certain filesystem calls are more compatible with restrictive hosting environments.
380
+ * CHANGED: Plugin is now ready to integate with [iControlWP automatic background updates system](http://www.icontrolwp.com/2013/11/manage-wordpress-automatic-background-updates-icontrolwp/).
381
+ * FIX: Login Protection Cooldown feature may not operate properly in certain scenarios.
382
+
383
+ = 2.1.5 =
384
+
385
+ * IMPROVED: Improved logic for Firewall whitelisting for pages and parameters to ensure whitelisting rules are followed.
386
+ * CHANGED: The whitelisting rule for posting pages/posts is only for the "content" and the firewall checking will apply to all other page parameters.
387
+
388
+ = 2.1.4 =
389
+
390
+ * FIX: When you run the Force Automatic Background Updates, it disables the plugins. This problem is now fixed.
391
+
392
+ = 2.1.2 =
393
+
394
+ * FIX: A bug that prevented auto-updates of this plugin.
395
+ * FIX: Not being able to hide translations and upgrade notices.
396
+ * ADDED: Tweaks to auto-update feature to allow interfacing with the iControlWP service to customize the auto update system.
397
+
398
+ = 2.1.0 =
399
+
400
+ * ADDED: A button that lets you run the WordPress Automatic Updates process on-demand (so you don't have to wait for WordPress cron).
401
+ * CHANGED: The plugin now sets more options to be turned on by default when the plugin is first activated.
402
+ * CHANGED: A lot of optimizations and code refactoring.
403
+
404
+ = 2.0.3 =
405
+
406
+ * FIX: Whoops, sorry, accidentally removed the option to toggle "disable file editing". It's back now.
407
+
408
+ = 2.0.2 =
409
+
410
+ * CHANGED: WordPress filters used to programmatically update whitelists now update the Login Protection IP whitelist
411
+
412
+ = 2.0.1 =
413
 
414
  * ADDED: Localization capabilities. All we need now are translators! [Go here to get started](http://translate.icontrolwp.com/).
415
  * ADDED: Option to mask the WordPress version so the real version is never publicly visible.
resources/css/{bootstrap-wpadmin.css → bootstrap-wpadmin-legacy.css} RENAMED
File without changes
resources/css/{icontrolwp-plugin.css → plugin.css} RENAMED
@@ -7,8 +7,18 @@
7
  .bootstrap-wpadmin .row {
8
  margin-left: 0;
9
  }
10
- #icontrolwp-icon {
11
- background: url("../images/icontrolwp_32x32.png") no-repeat 0px 3px transparent;
 
 
 
 
 
 
 
 
 
 
12
  }
13
  .wrap .icon32 {
14
  width: 32px;
@@ -72,9 +82,10 @@ p.code-description {
72
  font-style: italic;
73
  }
74
  .option_section {
75
- border: 1px solid #f2f2f2;
76
- border-radius: 8px 8px 8px 8px;
77
- margin-bottom: 8px;
 
78
  padding: 8px 10px;
79
  }
80
  .option_section label {
@@ -124,4 +135,8 @@ table#tbl_tbs_options_javascript td {
124
  /** OPTIONS PAGES **/
125
  .bootstrap-wpadmin .row.row_number_1 {
126
  padding-top: 18px;
 
 
 
 
127
  }
7
  .bootstrap-wpadmin .row {
8
  margin-left: 0;
9
  }
10
+ #pluginlogo_32 {
11
+ background: url("../images/pluginlogo_32x32.png") no-repeat 0px 3px transparent;
12
+ }
13
+ .pluginlogo_16 {
14
+ background: url("../images/pluginlogo_16x16.png") no-repeat 0px 3px transparent;
15
+ }
16
+ .page-header .header-icon32 {
17
+ display: inline-block;
18
+ float: left;
19
+ height: 40px;
20
+ vertical-align: middle;
21
+ width: 48px;
22
  }
23
  .wrap .icon32 {
24
  width: 32px;
82
  font-style: italic;
83
  }
84
  .option_section {
85
+ background-color: rgba(0, 0, 0, 0.008);
86
+ border: 1px solid #E6E6E6;
87
+ border-radius: 8px;
88
+ margin-bottom: 8px;
89
  padding: 8px 10px;
90
  }
91
  .option_section label {
135
  /** OPTIONS PAGES **/
136
  .bootstrap-wpadmin .row.row_number_1 {
137
  padding-top: 18px;
138
+ }
139
+
140
+ label input[type=checkbox] {
141
+ height: 16px !important;
142
  }
resources/css/worpit-plugin.css DELETED
@@ -1,119 +0,0 @@
1
- @CHARSET "ISO-8859-1";
2
-
3
- /* GENERAL STYLES */
4
-
5
- .bootstrap-wpadmin {
6
- }
7
- .bootstrap-wpadmin .row {
8
- margin-left: 0;
9
- }
10
- #worpit-icon {
11
- background: url("../images/worpit_32x32.png") no-repeat 0px 3px transparent;
12
- }
13
- /* Form elements */
14
- .bootstrap-wpadmin form fieldset {
15
- }
16
- .bootstrap-wpadmin .label {
17
- vertical-align: baseline !important;
18
- }
19
- .shortcode-usage {
20
- border-bottom: 1px solid #bbbbbb;
21
- margin-bottom: 10px;
22
- }
23
- p.code-description {
24
- font-style: italic;
25
- }
26
- /* Worpit promo */
27
- #worpit_button {
28
- background: url("../images/bright_squares.png") #EFEFEF;
29
- }
30
- #worpit_button {
31
- border: 1px solid #cccccc;
32
- border-radius: 4px;
33
- height: 190px;
34
- }
35
- #worpit_button:hover {
36
- box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.4);
37
- border: 1px solid transparent;
38
- }
39
- .row#developer_channel_promo #developer_channel_description .well {
40
- height: 275px;
41
- }
42
- .row#developer_channel_promo #developer_channel_form {
43
- border: 1px solid #EEE;
44
- border-radius: 6px;
45
- height: 315px; /* 275px + 20px-padding-x2 */
46
- }
47
- .row#developer_channel_promo #developer_channel_form h3 {
48
- padding: 10px 20px;
49
- }
50
-
51
- /** LESS PAGE **/
52
- .enabled_section {
53
- opacity: 1.0;
54
- }
55
- .disabled_section {
56
- opacity: 0.5;
57
- }
58
- /* BOOSTRAP SETTINGS PAGE STYLES */
59
- .wrap .icon32 {
60
- width: 32px;
61
- }
62
- .submit span {
63
- font-size: smaller;
64
- font-style: italic;
65
- }
66
- .option_section {
67
- border: 1px solid #f2f2f2;
68
- border-radius: 8px 8px 8px 8px;
69
- margin-bottom: 8px;
70
- padding: 8px 10px;
71
- }
72
- .option_section label {
73
- background-color: transparent;
74
- }
75
- .selected_item label {
76
- font-weight: bold;
77
- }
78
- .nonselected_item {
79
- background-color: transparent;
80
- }
81
- .nonselected_item label {
82
- font-weight: normal;
83
- }
84
- .option_section:hover {
85
- background-color: #ffffff;
86
- border: 1px dashed #BBBBBB;
87
- cursor: pointer;
88
- }
89
-
90
- .option_section.active {
91
- background-color: #f6f6f6;
92
- border-color: #dddddd;
93
- }
94
- table.tbl_tbs_options {
95
- width: 100%;
96
- border: 1px solid transparent;
97
- }
98
- table.tbl_tbs_options tr td {
99
- width: 49%;
100
- border: 1px solid transparent;
101
- }
102
-
103
- select#hlt_bootstrap_option {
104
- padding: 5px;
105
- border-radius:6px 6px 6px 6px;
106
- line-height: auto;
107
- height: 30px;
108
- width: 200px;
109
- }
110
-
111
- table#tbl_tbs_options_javascript td {
112
- vertical-align: top;
113
- width: 50%;
114
- }
115
-
116
- /** OPTIONS PAGES **/
117
- .bootstrap-wpadmin .row.row_number_1 {
118
- padding-top: 18px;
119
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/images/icontrolwp_16x16.png DELETED
Binary file
resources/images/icontrolwp_24x24.png DELETED
Binary file
resources/images/icontrolwp_32x32.png DELETED
Binary file
resources/images/pluginlogo_16x16.png ADDED
Binary file
resources/images/pluginlogo_24x24.png ADDED
Binary file
resources/images/pluginlogo_32x32.png ADDED
Binary file
resources/images/pluginlogo_64x64.png ADDED
Binary file
resources/spamblacklist.txt ADDED
@@ -0,0 +1,10549 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ _account
2
+ _article
3
+ _asics
4
+ _backup
5
+ _benefit
6
+ _blog
7
+ _bord
8
+ _build
9
+ _campaign
10
+ _coup
11
+ _data
12
+ _discount
13
+ _downtime
14
+ _e/
15
+ _emerg
16
+ _entr
17
+ _free
18
+ _help
19
+ _htm
20
+ _http
21
+ _index
22
+ _info
23
+ _java
24
+ _jersey
25
+ _key
26
+ _kino
27
+ _kit
28
+ _lacoste
29
+ _lauren
30
+ _link
31
+ _list
32
+ _load
33
+ _loan
34
+ _market
35
+ _misc
36
+ _news
37
+ _note
38
+ _occh
39
+ _online
40
+ _outlet
41
+ _porn
42
+ _post
43
+ _prof
44
+ _review
45
+ _sale
46
+ _scarpe
47
+ _select
48
+ _seo
49
+ _serv
50
+ _site
51
+ _spade
52
+ _store
53
+ _strat
54
+ _temp
55
+ _theme
56
+ _title
57
+ _track
58
+ _uptime
59
+ _url
60
+ _util
61
+ _vti
62
+ _weblog
63
+ ---
64
+ --and
65
+ --bag
66
+ --jack
67
+ --serv
68
+ --shut
69
+ --stor
70
+ --that
71
+ -(
72
+ -24.
73
+ -abercrombie-
74
+ -abercrombie.
75
+ -abercrombie/
76
+ -abercrombiefitch-
77
+ -abercrombiefitch.
78
+ -abercrombiefitch/
79
+ -acne-
80
+ -acne.
81
+ -acne/
82
+ -adsense-
83
+ -adsense.
84
+ -adsense/
85
+ -amateur-
86
+ -amateur.
87
+ -amateur/
88
+ -anal-
89
+ -anal.
90
+ -anal/
91
+ -anonymous-
92
+ -anonymous.
93
+ -anonymous/
94
+ -argente-
95
+ -argente.
96
+ -argente/
97
+ -armani-
98
+ -armani.
99
+ -armani/
100
+ -asics-
101
+ -asics.
102
+ -asics/
103
+ -auction-
104
+ -auction.
105
+ -auction/
106
+ -authentic-
107
+ -authentic.
108
+ -authentic/
109
+ -b2b
110
+ -backpain-
111
+ -backpain.
112
+ -backpain/
113
+ -beneficial-
114
+ -beneficial.
115
+ -beneficial/
116
+ -bioactive-
117
+ -bioactive.
118
+ -bioactive/
119
+ -bioactives-
120
+ -bioactives.
121
+ -bioactives/
122
+ -bitcoin-
123
+ -bitcoin.
124
+ -bitcoin/
125
+ -blog.
126
+ -blog/
127
+ -blogs.
128
+ -blogs/
129
+ -bluray-
130
+ -bluray.
131
+ -bluray/
132
+ -bodybuilding.
133
+ -bodybuilding/
134
+ -breathalyzer-
135
+ -broker.
136
+ -broker/
137
+ -buy.
138
+ -buy/
139
+ -car.co
140
+ -car.in
141
+ -casas-en-
142
+ -cash.
143
+ -cash/
144
+ -casino-
145
+ -casino.
146
+ -casino/
147
+ -cell-phone-
148
+ -charms.
149
+ -charms/
150
+ -cheap-
151
+ -cheap.
152
+ -cheap/
153
+ -cheapest-
154
+ -cheapest.
155
+ -cheapest/
156
+ -cheat-
157
+ -cheat.
158
+ -cheat/
159
+ -cia.co
160
+ -cigar-
161
+ -cigar.
162
+ -cigar/
163
+ -cigarette-
164
+ -cigarette.
165
+ -cigarette/
166
+ -cigarettes-
167
+ -cigarettes.
168
+ -cigarettes/
169
+ -cigars-
170
+ -cigars.
171
+ -cigars/
172
+ -click-
173
+ -click.
174
+ -click/
175
+ -co.jp
176
+ -cock-
177
+ -cock.
178
+ -cock/
179
+ -coin.
180
+ -coin/
181
+ -coins.
182
+ -coins/
183
+ -comfort-
184
+ -cosmetics.
185
+ -costume.
186
+ -coupon-
187
+ -data-recovery-
188
+ -deluxe-
189
+ -demo1
190
+ -diagnostic-
191
+ -dieta-
192
+ -dieta.
193
+ -dieta/
194
+ -directory.
195
+ -discount
196
+ -doktora-
197
+ -doktora.
198
+ -doktora/
199
+ -domination-
200
+ -domination.
201
+ -domination/
202
+ -download.
203
+ -download/
204
+ -dre.
205
+ -dre/
206
+ -drmartens-
207
+ -drmartens.
208
+ -drmartens/
209
+ -e-guide-
210
+ -easily-
211
+ -ebay
212
+ -enlargement.
213
+ -enlargement/
214
+ -entries/
215
+ -escort.
216
+ -escort/
217
+ -essay.
218
+ -essay/
219
+ -executive.
220
+ -executive/
221
+ -fantasia-
222
+ -fantasia.
223
+ -fashion-
224
+ -fashion.
225
+ -fashion/
226
+ -filmy
227
+ -finance.
228
+ -finance/
229
+ -financing.
230
+ -financing/
231
+ -fitch.
232
+ -fitch/
233
+ -for-adult
234
+ -for-sale
235
+ -for-u-
236
+ -for-u.
237
+ -for-u/
238
+ -for-you
239
+ -foreclose-
240
+ -foreclose.
241
+ -foreclose/
242
+ -foreclosed-
243
+ -foreclosed.
244
+ -foreclosed/
245
+ -foreclosure-
246
+ -foreclosure.
247
+ -foreclosure/
248
+ -fotograf.
249
+ -fotograf/
250
+ -fotografia.
251
+ -fotografia/
252
+ -fuck-
253
+ -fuck.
254
+ -fuck/
255
+ -fucked-
256
+ -fucked.
257
+ -fucked/
258
+ -fucker-
259
+ -fucker.
260
+ -fucker/
261
+ -fucking-
262
+ -fucking.
263
+ -fucking/
264
+ -fucks-
265
+ -fucks.
266
+ -fucks/
267
+ -fund-
268
+ -fund.
269
+ -fund/
270
+ -gambling-
271
+ -gambling.
272
+ -gambling/
273
+ -gaming-
274
+ -gaming.
275
+ -gaming/
276
+ -get-free-
277
+ -gifts-
278
+ -handbag-
279
+ -handbag.
280
+ -handbag/
281
+ -handbags-
282
+ -handbags.
283
+ -handbags/
284
+ -harley-davidson-
285
+ -herbal-
286
+ -herbal.
287
+ -herbal/
288
+ -hermes-
289
+ -hermes.
290
+ -hermes/
291
+ -hgh.
292
+ -hgh/
293
+ -income-
294
+ -income.
295
+ -income/
296
+ -infotain
297
+ -insurance.
298
+ -insurance/
299
+ -iphone-4-
300
+ -iphone-5-
301
+ -jacket-
302
+ -jacket.
303
+ -jacket/
304
+ -jackets-
305
+ -jackets.
306
+ -jackets/
307
+ -jeremy-scott-
308
+ -jerking-
309
+ -jerking.
310
+ -jerking/
311
+ -jersey-
312
+ -jersey.
313
+ -jersey/
314
+ -jerseys.
315
+ -jerseys/
316
+ -kredyt
317
+ -lacoste-
318
+ -link.
319
+ -link/
320
+ -linkbuild
321
+ -loan-
322
+ -loans-
323
+ -longchamp-
324
+ -longchamp.
325
+ -longchamp/
326
+ -lottery-
327
+ -lottery.
328
+ -lottery/
329
+ -lotto-
330
+ -lotto.
331
+ -lotto/
332
+ -lover-
333
+ -lover.
334
+ -lover/
335
+ -magazin-
336
+ -magazini-
337
+ -malware-
338
+ -malware.
339
+ -malware/
340
+ -marant-
341
+ -marc-jacobs-
342
+ -marcjacobs-
343
+ -mastery.
344
+ -mastery/
345
+ -mbt.
346
+ -mbt/
347
+ -mbts.
348
+ -mbts/
349
+ -men-jersey
350
+ -mens-jersey
351
+ -mens.
352
+ -metods-
353
+ -mlm.
354
+ -mlm/
355
+ -mlsp.
356
+ -mlsp/
357
+ -model.co
358
+ -models.co
359
+ -mortgage-
360
+ -new-car-
361
+ -newports/
362
+ -npn.
363
+ -npn/
364
+ -nude-
365
+ -nudes-
366
+ -oakley.
367
+ -oakley/
368
+ -occhiali/
369
+ -odejda-
370
+ -off-your-
371
+ -offshore-
372
+ -onlayn-
373
+ -online.
374
+ -online/
375
+ -order-at-
376
+ -outlet.
377
+ -outlet/
378
+ -payday-
379
+ -pictures.
380
+ -poker-
381
+ -poker.
382
+ -poker/
383
+ -pokie-
384
+ -pokie.
385
+ -pokie/
386
+ -pokies-
387
+ -pokies.
388
+ -pokies/
389
+ -pozew-
390
+ -prada-
391
+ -prada.
392
+ -prada/
393
+ -premium-
394
+ -premium.
395
+ -premium/
396
+ -price.
397
+ -price/
398
+ -programy-
399
+ -programy.
400
+ -programy/
401
+ -promo-
402
+ -promo.
403
+ -promo/
404
+ -promotions-
405
+ -promotions.
406
+ -promotions/
407
+ -purse.
408
+ -purse/
409
+ -purses.
410
+ -purses/
411
+ -pussy-
412
+ -rayban.
413
+ -rdnk-
414
+ -real-estate-
415
+ -realestate-
416
+ -remote-access
417
+ -remote-desktop
418
+ -repair.co
419
+ -review.co
420
+ -review/
421
+ -rims-
422
+ -rozwod-
423
+ -ru.
424
+ -sale.co
425
+ -sale.org
426
+ -salvia-
427
+ -scarpe-
428
+ -search-engine
429
+ -searchengine
430
+ -secrets-
431
+ -select-your-
432
+ -selection.
433
+ -selection/
434
+ -seo
435
+ -service.
436
+ -sexy-
437
+ -shiatsu.
438
+ -shoes.
439
+ -shop.co
440
+ -sigareta-
441
+ -sigareta.
442
+ -sigareta/
443
+ -sigarety-
444
+ -sigarety.
445
+ -sigarety/
446
+ -sims-3.
447
+ -sims-3/
448
+ -soma.
449
+ -soma/
450
+ -speed-up-
451
+ -store.
452
+ -store/
453
+ -strona-
454
+ -strona.
455
+ -strona/
456
+ -strony-
457
+ -strony.
458
+ -strony/
459
+ -sunglasses-
460
+ -sunglasses.
461
+ -sunglasses/
462
+ -supplement-
463
+ -supplement.
464
+ -supplement/
465
+ -supplements-
466
+ -supplements.
467
+ -supplements/
468
+ -suppliment-
469
+ -suppliment.
470
+ -suppliment/
471
+ -suppliments-
472
+ -suppliments.
473
+ -suppliments/
474
+ -symptoms-
475
+ -tax-attorney
476
+ -tax-relief
477
+ -tax-settlement
478
+ -teen-in-
479
+ -the-best-
480
+ -the-easiest-
481
+ -the-greatest-
482
+ -thunderstick-
483
+ -tips/
484
+ -top-info
485
+ -tours.co
486
+ -traffic.
487
+ -trainings.
488
+ -trainings/
489
+ -transpiration-
490
+ -treatment-
491
+ -tw.in
492
+ -uggs-
493
+ -uk.net
494
+ -vaginal-
495
+ -vendita-
496
+ -vuitton-
497
+ -watches.
498
+ -watches/
499
+ -wayfarer.
500
+ -web-pag
501
+ -web-site
502
+ -webhost.
503
+ -website-
504
+ -wedding-dress
505
+ -wedding-photo
506
+ -wheels-
507
+ -wholesale.
508
+ -wizard.co
509
+ -women-jersey
510
+ -womens.
511
+ -xchange
512
+ ・・
513
+ , ,
514
+ , .
515
+ ,,
516
+ ,.
517
+ ,"
518
+ ,ag
519
+ ,an
520
+ ,en
521
+ ,he
522
+ ,in
523
+ ,kat,
524
+ ,m,
525
+ ,me
526
+ ,no
527
+ ,of
528
+ ,on
529
+ ,th
530
+ ,title,
531
+ ,we
532
+ 、、
533
+ ::
534
+ :)!
535
+ ! .
536
+ !!!
537
+ !?’
538
+ !@#
539
+ ????
540
+ ?/pag
541
+ ?add
542
+ ?browse
543
+ ?domain
544
+ ?firma
545
+ ?free
546
+ ?kat
547
+ ?key
548
+ ?lang
549
+ ?sexy
550
+ ?store
551
+ ?title
552
+ ?twid
553
+ ?user
554
+ ?view
555
+ .%
556
+ .acgi
557
+ .adboard
558
+ .adsboard
559
+ .asp/
560
+ .azmya.
561
+ .baidu
562
+ .bioactive
563
+ .biz
564
+ .blogbox.be
565
+ .blogspace.
566
+ .bluray.
567
+ .causes-
568
+ .cfmx
569
+ .cgi
570
+ .com wild
571
+ .com/,
572
+ .com/%
573
+ .com/1.
574
+ .com/2.
575
+ .com/3.
576
+ .coupon
577
+ .credopa.in
578
+ .disposable-
579
+ .disposable/
580
+ .doorblog.jp
581
+ .executive-
582
+ .fake-
583
+ .fcgi
584
+ .filpan.ru
585
+ .filvce.in
586
+ .forum.
587
+ .frebvic.in
588
+ .freeforums.org
589
+ .games.pl
590
+ .hard-
591
+ .htm?
592
+ .htm/
593
+ .html?
594
+ .html/
595
+ .htn
596
+ .in/,
597
+ .in/1.
598
+ .in/2.
599
+ .in/3.
600
+ .info.
601
+ .info/,
602
+ .insanity-
603
+ .internet-
604
+ .jp/my/
605
+ .jp/shop
606
+ .longchamp-
607
+ .magix.net
608
+ .mobi/?
609
+ .moncler-
610
+ .net/online
611
+ .net/user
612
+ .nikeshox
613
+ .on-demand
614
+ .online.pl
615
+ .online.ws
616
+ .or.kr
617
+ .org/,
618
+ .org/user
619
+ .outlet.co
620
+ .php?
621
+ .php/?
622
+ .pl?
623
+ .pl/?
624
+ .pl/#
625
+ .pl/1.
626
+ .pl/2.
627
+ .pl/3.
628
+ .pl/content
629
+ .pl/member
630
+ .pl/profile
631
+ .pl/user
632
+ .pl#
633
+ .rar.
634
+ .redirects.
635
+ .rekla
636
+ .remote-desktop
637
+ .remotedesktop
638
+ .royal-
639
+ .rshacks.
640
+ .ru?
641
+ .ru/,
642
+ .ru/?
643
+ .ru/#
644
+ .ru/1.
645
+ .ru/2.
646
+ .ru/3.
647
+ .ru/content
648
+ .ru/forum
649
+ .ru/image
650
+ .ru/member
651
+ .ru/profile
652
+ .ru/service
653
+ .ru/user
654
+ .ru#
655
+ .sirenos.in
656
+ .smiley
657
+ .sunglasses-
658
+ .supreme-
659
+ .thearticle
660
+ .travel.pl
661
+ .twilight-
662
+ .univer.
663
+ .us/user
664
+ .webs.co
665
+ .worktop.
666
+ .worktops.
667
+ .za/image
668
+ ''
669
+ )-
670
+ [...
671
+ [/color
672
+ [/move
673
+ [/url
674
+ [color
675
+ [move
676
+ [url
677
+ @123
678
+ @mail-
679
+ @toke.
680
+ *@
681
+ /-_
682
+ /?cat
683
+ /?doc
684
+ /?l1
685
+ /?l2
686
+ /?new
687
+ /?p=
688
+ /?pag
689
+ /?tag
690
+ /?uid
691
+ /.wd/
692
+ //123.
693
+ //aaa-
694
+ //aaa.
695
+ //act-
696
+ //act.
697
+ //affordable
698
+ //article
699
+ //best
700
+ //bitcoin
701
+ //businessdaily
702
+ //buy
703
+ //cheap
704
+ //compare
705
+ //contact
706
+ //eee
707
+ //escort
708
+ //forum
709
+ //free
710
+ //friend
711
+ //gay
712
+ //generic
713
+ //groups
714
+ //hgh
715
+ //images/
716
+ //income
717
+ //leverage
718
+ //official
719
+ //onsale
720
+ //pagina
721
+ //podcast-
722
+ //podcast.
723
+ //prosport
724
+ //reality
725
+ //royal-
726
+ //ru.
727
+ //shop
728
+ //test
729
+ //vpn-
730
+ //vpn.
731
+ //webpage
732
+ //website
733
+ //webstore
734
+ //wp-
735
+ /10.htm
736
+ /11.htm
737
+ /12.htm
738
+ /13.htm
739
+ /14.htm
740
+ /15.htm
741
+ /100mg
742
+ /a-
743
+ /a#
744
+ /abercrombie-
745
+ /abercrombie.
746
+ /about.
747
+ /acai
748
+ /acidreflux-
749
+ /acidreflux.
750
+ /add.
751
+ /addfeed/
752
+ /admin/
753
+ /administration/
754
+ /adorable-
755
+ /adorable.
756
+ /ads/
757
+ /affordable-
758
+ /affordable.
759
+ /airmax-
760
+ /airmax.
761
+ /alimenty/
762
+ /allimage/
763
+ /anonymous-
764
+ /anonymous.
765
+ /answer-
766
+ /answer.
767
+ /armani-
768
+ /armani.
769
+ /around.
770
+ /asics-
771
+ /asics.
772
+ /asp/
773
+ /asthma-
774
+ /asthma.
775
+ /attachments/
776
+ /authentic
777
+ /baby-
778
+ /baby.
779
+ /babydoll-
780
+ /babydoll.
781
+ /bag.sh/
782
+ /bags/
783
+ /banner-
784
+ /banner.
785
+ /banners-
786
+ /banners.
787
+ /bazar-
788
+ /bazar.
789
+ /bbs/
790
+ /best-
791
+ /best.
792
+ /better-
793
+ /better.
794
+ /birkenstock-
795
+ /birkenstock.
796
+ /birkenstocks-
797
+ /birkenstocks.
798
+ /birkin.
799
+ /bitcoin-
800
+ /black-friday
801
+ /blog:
802
+ /blog.
803
+ /blogid
804
+ /bloglist/
805
+ /blogs/
806
+ /board/
807
+ /bookmark-
808
+ /bookmark.
809
+ /bookmarks-
810
+ /bookmarks.
811
+ /brand1
812
+ /brand2
813
+ /brand3
814
+ /brand4
815
+ /brand5
816
+ /burberry-
817
+ /burberry1
818
+ /burberry2
819
+ /burberry3
820
+ /burberry4
821
+ /bustier-
822
+ /bustier.
823
+ /buy-
824
+ /buy.
825
+ /bvlgari-
826
+ /bvlgari.
827
+ /cache/
828
+ /campaign-
829
+ /campaign.
830
+ /campaign/
831
+ /campaigns-
832
+ /campaigns.
833
+ /campaigns/
834
+ /canadagoose-
835
+ /canadagoose.
836
+ /canadagoose/
837
+ /carinsur-
838
+ /carinsur.
839
+ /carinsurance-
840
+ /carinsurance.
841
+ /cartier-
842
+ /cartier.
843
+ /casino
844
+ /categories-
845
+ /category-
846
+ /chanel-
847
+ /chanel.
848
+ /chat/
849
+ /chaussure-
850
+ /chaussure.
851
+ /chaussures-
852
+ /chaussures.
853
+ /cheap-
854
+ /cheap.
855
+ /china.
856
+ /chrome/
857
+ /chrome=
858
+ /cigar-
859
+ /cigar.
860
+ /cigarette-
861
+ /cigarette.
862
+ /cigarettes-
863
+ /cigarettes.
864
+ /cigars-
865
+ /cigars.
866
+ /ck-
867
+ /ck.
868
+ /cl/
869
+ /cld-
870
+ /cld.
871
+ /clearance/
872
+ /clrb-
873
+ /clrb.
874
+ /coach-
875
+ /coach.
876
+ /coach/
877
+ /coachpurse-
878
+ /coachpurse.
879
+ /coachpurses-
880
+ /coachpurses.
881
+ /commodity-
882
+ /commodity.
883
+ /common/
884
+ /conf-
885
+ /conf.
886
+ /conf/
887
+ /config-
888
+ /config.
889
+ /config/
890
+ /configura-
891
+ /configura.
892
+ /configura/
893
+ /configuration-
894
+ /configuration.
895
+ /configuration/
896
+ /contact.
897
+ /content/
898
+ /coupon/
899
+ /coupons/
900
+ /crimea-
901
+ /css/
902
+ /customcontrol
903
+ /customer-care.
904
+ /customer-care/
905
+ /customercare-
906
+ /customercare.
907
+ /damen-moncler
908
+ /dat/
909
+ /data/
910
+ /datebase-
911
+ /datebase.
912
+ /db/
913
+ /dbase/
914
+ /dg-
915
+ /dg.
916
+ /diary-
917
+ /diary.
918
+ /diesel-
919
+ /diet.
920
+ /dieta.
921
+ /dior.
922
+ /div/
923
+ /dlia/
924
+ /dmg/
925
+ /dolce-gabbana
926
+ /doudoun.
927
+ /doudoune.
928
+ /download.
929
+ /drmartens-
930
+ /drug
931
+ /dsquared-
932
+ /dsquared.
933
+ /duvetica.
934
+ /economical-
935
+ /empower-
936
+ /en.
937
+ /eng/index
938
+ /engine/
939
+ /errorx/
940
+ /escort-
941
+ /escort.
942
+ /escorts-
943
+ /escorts.
944
+ /executive-
945
+ /extreme-
946
+ /fashion-
947
+ /features-
948
+ /feed/
949
+ /feeds/
950
+ /fendi-
951
+ /fendi.
952
+ /ferragamo-
953
+ /ferragamo.
954
+ /file/
955
+ /files/
956
+ /filmy
957
+ /finance.
958
+ /financing.
959
+ /flash/
960
+ /foot-care
961
+ /form.
962
+ /forum/
963
+ /forum1
964
+ /fotka.
965
+ /foto.
966
+ /fpdb/
967
+ /free/
968
+ /fuck-
969
+ /fuck.
970
+ /fucked-
971
+ /fucked.
972
+ /fucker-
973
+ /fucker.
974
+ /fucking-
975
+ /fucking.
976
+ /fucks-
977
+ /fucks.
978
+ /futbol-
979
+ /futbol/
980
+ /gagajapan-
981
+ /gagajapan.
982
+ /gagamilano-
983
+ /gagamilano.
984
+ /gekiyasu
985
+ /get-free
986
+ /get-widget
987
+ /getwidget
988
+ /gh0/
989
+ /gh1/
990
+ /glowna.
991
+ /gold.
992
+ /graphics/
993
+ /group1
994
+ /group2
995
+ /group3
996
+ /groups/
997
+ /grow-your
998
+ /gry-
999
+ /gry.
1000
+ /gucci-
1001
+ /gucci.
1002
+ /guest-book
1003
+ /guestbook
1004
+ /guide-
1005
+ /haglofs-
1006
+ /haglofs.
1007
+ /handle/
1008
+ /headlines/
1009
+ /hentai
1010
+ /hermes-
1011
+ /hermes.
1012
+ /herveleger
1013
+ /hgh-
1014
+ /hgh.
1015
+ /hiend
1016
+ /hire-
1017
+ /hollister-
1018
+ /hollister.
1019
+ /hollister/
1020
+ /home.
1021
+ /hot.
1022
+ /hotdeal
1023
+ /ii/
1024
+ /images-
1025
+ /images.
1026
+ /img/
1027
+ /img1/
1028
+ /img2/
1029
+ /inc-meta
1030
+ /inc/
1031
+ /include/
1032
+ /includes/
1033
+ /index-0
1034
+ /index-1
1035
+ /index-2
1036
+ /index-3
1037
+ /index-4
1038
+ /index-5
1039
+ /index.asp
1040
+ /index.php
1041
+ /index0
1042
+ /index1
1043
+ /index2
1044
+ /index3
1045
+ /index4
1046
+ /index5
1047
+ /indexdic
1048
+ /info-
1049
+ /info.
1050
+ /infopage/
1051
+ /infopages/
1052
+ /install/
1053
+ /insurance.
1054
+ /iphone-case
1055
+ /iss.php
1056
+ /jacket-
1057
+ /jacket.
1058
+ /jbs-
1059
+ /jbs.
1060
+ /jersey-
1061
+ /jersey.
1062
+ /jerseys-
1063
+ /jerseys.
1064
+ /job.
1065
+ /join.
1066
+ /jordan.
1067
+ /jordan1
1068
+ /jordan2
1069
+ /jordan3
1070
+ /jordan4
1071
+ /jordan5
1072
+ /js.
1073
+ /js/
1074
+ /just.
1075
+ /kat,
1076
+ /kd6
1077
+ /kinder-moncler
1078
+ /kitchenknife-
1079
+ /kitchenknife.
1080
+ /kitchenknives-
1081
+ /kitchenknives.
1082
+ /kommentar
1083
+ /konsultan
1084
+ /kredit
1085
+ /kredyt
1086
+ /lacoste-
1087
+ /lang-es/
1088
+ /latestmk-
1089
+ /latestmk.
1090
+ /legal/
1091
+ /libs/
1092
+ /lijst/
1093
+ /limewire
1094
+ /lingerie.
1095
+ /link-
1096
+ /link.
1097
+ /link/
1098
+ /linkdetail
1099
+ /linknum
1100
+ /links-
1101
+ /links.
1102
+ /list.
1103
+ /loans
1104
+ /locale/
1105
+ /logos/
1106
+ /longchamp-
1107
+ /louboutin-
1108
+ /love-fail
1109
+ /love-life
1110
+ /love-quote
1111
+ /lunette-
1112
+ /lunette.
1113
+ /lunettes-
1114
+ /lunettes.
1115
+ /lv.
1116
+ /lv/
1117
+ /mailer/
1118
+ /maillot-
1119
+ /maillot.
1120
+ /malware/
1121
+ /manolo-blahnik
1122
+ /manoloblahnik
1123
+ /massage
1124
+ /mbt-
1125
+ /mbt.
1126
+ /mcm.
1127
+ /med-
1128
+ /mediawiki/
1129
+ /medical
1130
+ /medication-
1131
+ /member/
1132
+ /members-
1133
+ /members.
1134
+ /members/
1135
+ /membership-
1136
+ /membership.
1137
+ /menu.
1138
+ /mk-us/
1139
+ /mkshop-
1140
+ /mkshop.
1141
+ /mlsp-
1142
+ /mlsp.
1143
+ /mlsp/
1144
+ /mobile/
1145
+ /module/
1146
+ /modules/
1147
+ /moncler-
1148
+ /moncler.
1149
+ /moncler/
1150
+ /montblanc.
1151
+ /mortgage
1152
+ /mulberry-
1153
+ /mulberry.
1154
+ /myspace/
1155
+ /n.php
1156
+ /nailart-
1157
+ /nailart.
1158
+ /nailart/
1159
+ /natverk/
1160
+ /netcat
1161
+ /netwerk/
1162
+ /network/
1163
+ /new.
1164
+ /newbalance
1165
+ /newports-
1166
+ /newports.
1167
+ /news.
1168
+ /newsletter/
1169
+ /newsletters/
1170
+ /nihon
1171
+ /nike-
1172
+ /nike.
1173
+ /nikefree
1174
+ /niketn
1175
+ /ninnki
1176
+ /no-excuse
1177
+ /node/
1178
+ /north-face
1179
+ /north-face-
1180
+ /northface-
1181
+ /northface.
1182
+ /novinki-
1183
+ /novinki.
1184
+ /npn-
1185
+ /npn.
1186
+ /oakley-
1187
+ /oakley.
1188
+ /oakley/
1189
+ /oakleycan
1190
+ /offering/
1191
+ /ok.php
1192
+ /online.
1193
+ /orderpage/
1194
+ /orgasm
1195
+ /other-
1196
+ /other.
1197
+ /outils/
1198
+ /page1.
1199
+ /page2.
1200
+ /page3.
1201
+ /page4.
1202
+ /page5.
1203
+ /pages-
1204
+ /pages.
1205
+ /pandorabead.
1206
+ /pantie-
1207
+ /panties-
1208
+ /panty-
1209
+ /php.
1210
+ /piece-
1211
+ /piece.
1212
+ /popup
1213
+ /porn
1214
+ /post:
1215
+ /postinfo-
1216
+ /postinfo.
1217
+ /pozew
1218
+ /prada-
1219
+ /prada.
1220
+ /premium-
1221
+ /premium.
1222
+ /pricing-
1223
+ /pricing.
1224
+ /privat-
1225
+ /private-
1226
+ /private.
1227
+ /private/
1228
+ /product/0/
1229
+ /produkter/
1230
+ /proficient-
1231
+ /profil-
1232
+ /profil.
1233
+ /profil/
1234
+ /profile-
1235
+ /profile.
1236
+ /profile/
1237
+ /prolist
1238
+ /property-
1239
+ /property.
1240
+ /prozac
1241
+ /pufy
1242
+ /pumps-
1243
+ /pumps.
1244
+ /q.
1245
+ /ra.php
1246
+ /ray-ban-
1247
+ /ray-ban.
1248
+ /ray-ban/
1249
+ /rayban-
1250
+ /rayban.
1251
+ /rayban/
1252
+ /read.php
1253
+ /readme.
1254
+ /readnews.
1255
+ /recap/
1256
+ /refreshers.
1257
+ /remote-desktop
1258
+ /remotedesktop
1259
+ /ri.ms
1260
+ /rozwod
1261
+ /rss.xml
1262
+ /ru/news/
1263
+ /sac-
1264
+ /sac.
1265
+ /sale-
1266
+ /sales-
1267
+ /salvia/
1268
+ /scarpe-
1269
+ /sconfig/
1270
+ /scripts-
1271
+ /scripts/
1272
+ /secure/
1273
+ /sendform/
1274
+ /seo
1275
+ /sex
1276
+ /show/
1277
+ /sigareta-
1278
+ /sigareta.
1279
+ /sigarety-
1280
+ /sigarety.
1281
+ /sims-3.
1282
+ /sinsaku
1283
+ /site/
1284
+ /site/ebay
1285
+ /sitemap.
1286
+ /siteold/
1287
+ /soft/
1288
+ /soma-
1289
+ /soma.
1290
+ /soma/
1291
+ /special-
1292
+ /special.
1293
+ /specialprojects-
1294
+ /specialprojects.
1295
+ /specials-
1296
+ /specials.
1297
+ /start.
1298
+ /strona-
1299
+ /strona/
1300
+ /strony-
1301
+ /strony/
1302
+ /stuff.
1303
+ /suggestions-
1304
+ /sunglasses-
1305
+ /sunglasses.
1306
+ /swf/
1307
+ /syaneru
1308
+ /systemdb.
1309
+ /sysuser/
1310
+ /tagged/
1311
+ /telecharger-
1312
+ /telecharger.
1313
+ /temp/
1314
+ /temp0
1315
+ /temp1
1316
+ /temp2
1317
+ /temp3
1318
+ /templates/
1319
+ /test.
1320
+ /the-first
1321
+ /the-sale
1322
+ /the-secret
1323
+ /the-shock
1324
+ /thebest
1325
+ /themes/
1326
+ /thesecret.
1327
+ /thread-
1328
+ /tiffany-
1329
+ /tiffany.
1330
+ /timberland-
1331
+ /timberland.
1332
+ /title,
1333
+ /tmp/
1334
+ /toms-
1335
+ /toms.
1336
+ /top100.
1337
+ /trac/ticket/
1338
+ /trackback
1339
+ /twilight-
1340
+ /ugg-
1341
+ /ugg/
1342
+ /uggs-
1343
+ /uggs.
1344
+ /uggsal/
1345
+ /update/
1346
+ /upload-
1347
+ /upload/
1348
+ /uploadfiles/
1349
+ /uploads/
1350
+ /url/
1351
+ /usa.
1352
+ /user-
1353
+ /user:
1354
+ /user.
1355
+ /usuario:
1356
+ /vb/
1357
+ /viewstory
1358
+ /visit.
1359
+ /visite.
1360
+ /vuitton-
1361
+ /vuitton.
1362
+ /vuittonpascher-
1363
+ /vuittonpascher.
1364
+ /wayfarer-
1365
+ /wayfarer.
1366
+ /web-design/
1367
+ /web0/
1368
+ /web1/
1369
+ /web2/
1370
+ /web3/
1371
+ /wedding.
1372
+ /wholesale-
1373
+ /wholesale.
1374
+ /wo.
1375
+ /woolrich-
1376
+ /woolrich.
1377
+ /wp-admin
1378
+ /wp-content
1379
+ /wp-image
1380
+ /wp-include
1381
+ /wp-list
1382
+ /wp-site
1383
+ /wpadmin
1384
+ /wpcontent
1385
+ /wpimage
1386
+ /wpinclude
1387
+ /wplist
1388
+ /wpsite
1389
+ /ww.
1390
+ /www/
1391
+ /x.co
1392
+ /xchange
1393
+ /xe/
1394
+ /xml/
1395
+ /ya.
1396
+ /yabb
1397
+ /yours.
1398
+ /z.
1399
+ /zumba-
1400
+ \xa9
1401
+ \xc3
1402
+ &#070;&#069;&#078;&#068;&#073;
1403
+ &#072;&#101;&#114;&#109;&#101;&#115;
1404
+ &#080;&#097;&#117;&#108;&#032;&#083;&#109;&#105;&#116;&#104;
1405
+ &#116;&#105;&#109;&#098;&#101;&#114;&#108;&#097;&#110;&#100;
1406
+ &#969;
1407
+ &#1072;
1408
+ &#1075;
1409
+ &#12456;&#12450;&#12510;&#12483;&#12463;&#12473;
1410
+ &#12488;&#12453;&#12511;
1411
+ &#12488;&#12522;&#12540;&#12496;&#12540;&#12481;
1412
+ &#12490;&#12452;&#12461;
1413
+ &#12491;&#12517;&#12540;&#12496;&#12521;&#12531;&#12473;
1414
+ &#12503;&#12525;&#12514;
1415
+ &#12509;&#12540;&#12523;&#12473;&#12511;&#12473;
1416
+ &#12511;&#12517;&#12454;
1417
+ &#12524;&#12503;&#12522;&#12459;
1418
+ &#12525;&#12540;&#12531;
1419
+ &#20605;&#29289;
1420
+ &#21033;
1421
+ &#36001;&#24067;
1422
+ &#37329;
1423
+ &amp;amp
1424
+ &article
1425
+ &eþh;
1426
+ &kappa;
1427
+ &omicron;
1428
+ &x6
1429
+ &x7
1430
+ #/a
1431
+ #file
1432
+ #random
1433
+ %7c
1434
+ %20-%20
1435
+ %20co
1436
+ %20on
1437
+ %20zappo
1438
+ %anchor%
1439
+ %d8%
1440
+ %e0%
1441
+ %titel%
1442
+ %title%
1443
+ %titlet%
1444
+ %u2019
1445
+ %url%
1446
+ +cheap
1447
+ +clearance
1448
+ +handbag
1449
+ +jersey
1450
+ +louboutin
1451
+ +outlet
1452
+ <a>
1453
+ =blog
1454
+ =captcha
1455
+ =node
1456
+ =profile
1457
+ =read
1458
+ =space
1459
+ =thread
1460
+ =utf8
1461
+ =view
1462
+ >.}
1463
+ >casino
1464
+ >cheap
1465
+ >enter
1466
+ >fuck
1467
+ >gluten
1468
+ >herpes
1469
+ >longchamp
1470
+ >pokie
1471
+ >sensual
1472
+ >shopping
1473
+ >ugg
1474
+ >woolr
1475
+ |chi
1476
+ |dal
1477
+ |det
1478
+ |for
1479
+ |per
1480
+ |porn
1481
+ |year
1482
+ |yr
1483
+ 000mail
1484
+ 1-1.
1485
+ 1.cfm
1486
+ 1.in
1487
+ 1@1
1488
+ 1@2
1489
+ 1@3
1490
+ 1big
1491
+ 1bodog
1492
+ 1c.in
1493
+ 1minutesite
1494
+ 1stop
1495
+ 1test
1496
+ 1to1
1497
+ 2-global
1498
+ 2.cfm
1499
+ 2.in
1500
+ 2@1
1501
+ 2@2
1502
+ 2@3
1503
+ 2bj.ru
1504
+ 2c.in
1505
+ 2global
1506
+ 2itb
1507
+ 2sale
1508
+ 2test
1509
+ 2u.org
1510
+ 3.cfm
1511
+ 3.in
1512
+ 3@1
1513
+ 3@2
1514
+ 3@3
1515
+ 3j3j3
1516
+ 3test
1517
+ 3ww3
1518
+ 4all
1519
+ 4cheap
1520
+ 4ever
1521
+ 4firefall
1522
+ 4less
1523
+ 4sale
1524
+ 4u.co
1525
+ 4you.
1526
+ 5health
1527
+ 7handbag
1528
+ 7purse
1529
+ 8handbag
1530
+ 8purse
1531
+ 49ers jersey
1532
+ 49ers online
1533
+ 49ers-jersey
1534
+ 49ers-online
1535
+ 49ersjersey
1536
+ 49ersonline
1537
+ 100% legit
1538
+ 100mg.
1539
+ 111.
1540
+ 111@
1541
+ 123.co
1542
+ 123.in
1543
+ 123@
1544
+ 222.co
1545
+ 222.in
1546
+ 365.co
1547
+ 365.in
1548
+ 404.php
1549
+ 911.co
1550
+ 911.in
1551
+ 2007.co
1552
+ 2008.co
1553
+ 2009.co
1554
+ 2010.co
1555
+ 2011.co
1556
+ 2012.co
1557
+ 2013.co
1558
+ 2013.de
1559
+ 2013.in
1560
+ 2013.or
1561
+ 2013baby
1562
+ 2013x.
1563
+ 2014.co
1564
+ 2014.de
1565
+ 2014.in
1566
+ 2014.or
1567
+ 2014baby
1568
+ 123456789
1569
+ ¥·¥
1570
+ ¥°¥
1571
+ a lots
1572
+ a-cell-phone
1573
+ a-lots
1574
+ a-powerful-way
1575
+ a.pri.l
1576
+ ã©
1577
+ a1.co
1578
+ â€
1579
+ aaa replica
1580
+ aaa-replica
1581
+ aaabbb
1582
+ abcwatch
1583
+ abdominaux
1584
+ abercrombie deutsch
1585
+ abercrombie kid
1586
+ abercrombie man
1587
+ abercrombie men
1588
+ abercrombie outlet
1589
+ abercrombie uomo
1590
+ abercrombie wom
1591
+ abercrombie-deutsch
1592
+ abercrombie-ital
1593
+ abercrombie-kid
1594
+ abercrombie-man
1595
+ abercrombie-men
1596
+ abercrombie-outlet
1597
+ abercrombie-uomo
1598
+ abercrombie-wom
1599
+ abercrombiee
1600
+ abercrombieital
1601
+ abercrombiekid
1602
+ abercrombieman
1603
+ abercrombiemen
1604
+ abercrombieoutlet
1605
+ abercrombieuomo
1606
+ abercrombiewom
1607
+ abilify
1608
+ about marijuana
1609
+ about_
1610
+ about-marijuana
1611
+ about/date
1612
+ abouther
1613
+ acai-
1614
+ acaiberry
1615
+ accouchement
1616
+ accounts receiv
1617
+ accounts-receiv
1618
+ accupril
1619
+ accutane
1620
+ acertemail.co
1621
+ acetazolamide
1622
+ acid-reflux
1623
+ acnecyst
1624
+ acnetreatment
1625
+ acomplia
1626
+ activation code
1627
+ activity/p/
1628
+ actonel
1629
+ actual effort
1630
+ actual thank
1631
+ actual-effort
1632
+ actual-thank
1633
+ actually thank
1634
+ actually-thank
1635
+ acutual
1636
+ acyclovir
1637
+ ad-wiki
1638
+ adbeat distrib
1639
+ adbeat expert
1640
+ adbeat trial
1641
+ adbeat-distrib
1642
+ adbeat-expert
1643
+ adbeat-trial
1644
+ adbeatdistrib
1645
+ adbeatexpert
1646
+ adbeattrial
1647
+ addarticle
1648
+ adderall
1649
+ adderoll
1650
+ addicted-to
1651
+ addidas
1652
+ additionay
1653
+ adenosyl
1654
+ adidas adizero
1655
+ adidas fotball
1656
+ adidas jeremy
1657
+ adidas js
1658
+ adidas origin
1659
+ adidas out
1660
+ adidas porsche
1661
+ adidas shop
1662
+ adidas slip
1663
+ adidas super
1664
+ adidas uomo
1665
+ adidas wing
1666
+ adidas-adizero
1667
+ adidas-corner
1668
+ adidas-fotball
1669
+ adidas-jeremy
1670
+ adidas-js
1671
+ adidas-orig
1672
+ adidas-out
1673
+ adidas-porsche
1674
+ adidas-shop
1675
+ adidas-slip
1676
+ adidas-super
1677
+ adidas-uomo
1678
+ adidas-wing
1679
+ adidashop
1680
+ adidasjeremy
1681
+ adidasjs
1682
+ adidasorig
1683
+ adidasoutlet
1684
+ adidasporsche
1685
+ adidasshop
1686
+ adidasslip
1687
+ adidassuper
1688
+ adidasuomo
1689
+ adidaswing
1690
+ adipex
1691
+ admin.cfm
1692
+ admin5
1693
+ ados populaire
1694
+ ados-populaire
1695
+ adospopulaire
1696
+ ads ad
1697
+ ads crack
1698
+ ads live
1699
+ ads-ad
1700
+ ads-crack
1701
+ ads-live
1702
+ adscrack
1703
+ adsjeremy
1704
+ adslive
1705
+ adsplus
1706
+ adsuse
1707
+ adswings
1708
+ adult baseball
1709
+ adult girl
1710
+ adult toy
1711
+ adult-baseball
1712
+ adult-girl
1713
+ adult-sex
1714
+ adult-story
1715
+ adult-toy
1716
+ adultdating
1717
+ adultgirl
1718
+ adultsex
1719
+ adulttoy
1720
+ advantages_of
1721
+ advantages-of
1722
+ advert-market
1723
+ advertise your
1724
+ advertise-your
1725
+ advertising-research
1726
+ advok
1727
+ adwings
1728
+ adwokacka
1729
+ adwokat
1730
+ adwords
1731
+ aff.php
1732
+ affiliate link
1733
+ affiliate-link
1734
+ affiliatelink
1735
+ affliction classic
1736
+ affliction jean
1737
+ affliction men
1738
+ affliction new
1739
+ affliction offer
1740
+ affliction-classic
1741
+ affliction-jean
1742
+ affliction-men
1743
+ affliction-new
1744
+ affliction-offer
1745
+ afflictionclassic
1746
+ afflictionjean
1747
+ afflictionmen
1748
+ afflictionnew
1749
+ afflictionoffer
1750
+ affordable handbag
1751
+ affordable-handbag
1752
+ african-canadian-model
1753
+ africancanadianmodel
1754
+ ãƒ
1755
+ age.webeden
1756
+ age|
1757
+ agedepot
1758
+ ageless female
1759
+ ageless male
1760
+ ageless men
1761
+ ageless women
1762
+ ageless-female
1763
+ ageless-male
1764
+ ageless-men
1765
+ ageless-women
1766
+ agencje-
1767
+ agent denim
1768
+ agent direct
1769
+ agent-denim
1770
+ agent-direct
1771
+ agentdenim
1772
+ ago|
1773
+ âgrâve
1774
+ aint goin
1775
+ aint-goin
1776
+ air max
1777
+ air-jorda
1778
+ air-max
1779
+ air-yeezy
1780
+ airjorda
1781
+ airmax
1782
+ airmax_
1783
+ airport--
1784
+ airport-transport
1785
+ airyeezy
1786
+ aitaiwan
1787
+ akkuschrauber
1788
+ aklotr
1789
+ aksudmias
1790
+ albuterol
1791
+ alendronate
1792
+ alkotla
1793
+ all-about-the
1794
+ allbestedmed
1795
+ allbestmed
1796
+ allianz/
1797
+ allright
1798
+ alluring escort
1799
+ alluring-escort
1800
+ allworkhome
1801
+ alprazolam
1802
+ amateur-homemade
1803
+ amateur.
1804
+ amateurhomemade
1805
+ amateurs.
1806
+ amazing post
1807
+ amazing-post
1808
+ amazn.co
1809
+ amazon.cm
1810
+ ambien
1811
+ ametuer
1812
+ aminocare
1813
+ amitriptyline
1814
+ amorti dynamique
1815
+ amorti-dynamique
1816
+ amour gratuite
1817
+ amour-gratuite
1818
+ amoxicil
1819
+ amoxil
1820
+ amzon.co
1821
+ an0n.me
1822
+ anabolic
1823
+ anal sex
1824
+ anal-sex
1825
+ analsex
1826
+ and-special
1827
+ andcloth
1828
+ andcoupon
1829
+ andjourney
1830
+ andmerciful
1831
+ androidclan
1832
+ androidmp3
1833
+ aneswr
1834
+ angebote
1835
+ animalbased
1836
+ ankle bootie
1837
+ ankle-bootie
1838
+ anklebootie
1839
+ ano.gd
1840
+ anonymous-download
1841
+ anonymousvpn
1842
+ answertraffic
1843
+ anti-aging
1844
+ antiage
1845
+ antiaging
1846
+ antispam
1847
+ antivirus/index
1848
+ antivirussen
1849
+ anuncios
1850
+ anү
1851
+ apartamentow
1852
+ apbd_sjs
1853
+ apex bionic
1854
+ apex-bionic
1855
+ apexbionic
1856
+ app.lk
1857
+ app.php
1858
+ apple-unlock
1859
+ appleunlock
1860
+ appro-chait
1861
+ appyourself
1862
+ apr.i.l
1863
+ aquarius-compat
1864
+ arcteryx-jp
1865
+ arcteryx-sale
1866
+ arcteryxjp
1867
+ arcteryxsale
1868
+ are added-
1869
+ areplica
1870
+ aricept
1871
+ aripiprex
1872
+ armagard.co
1873
+ armani costume
1874
+ armani-costume
1875
+ armanito
1876
+ aroma-paradise
1877
+ artemfrolov
1878
+ article content
1879
+ article dude
1880
+ article plus
1881
+ article-buzz
1882
+ article-content
1883
+ article-dude
1884
+ article-plus
1885
+ article,i
1886
+ article!
1887
+ article.co
1888
+ article.in
1889
+ article.net
1890
+ article.org
1891
+ article.php
1892
+ article/suggest
1893
+ articlebuzz
1894
+ articlepowa
1895
+ articles.co
1896
+ articles.in
1897
+ articles.net
1898
+ articles.org
1899
+ articlesub
1900
+ articulatio
1901
+ artikel
1902
+ artykul
1903
+ asd@
1904
+ asdasd
1905
+ asdf
1906
+ asicsshoe
1907
+ asikkusu
1908
+ aso expei
1909
+ asos coupon
1910
+ asos-coupon
1911
+ asoscoupon
1912
+ asp?folder
1913
+ asp?id
1914
+ asphalt8cheat
1915
+ asphalt8hack
1916
+ aspiring blog
1917
+ aspiring-blog
1918
+ assistance informatique
1919
+ assistance-inform
1920
+ assistance-informatique
1921
+ associate link
1922
+ associate-link
1923
+ assortiment
1924
+ astounding1
1925
+ astounding2
1926
+ astounding3
1927
+ astounding4
1928
+ astounding5
1929
+ astral-diamond
1930
+ aswenr
1931
+ at web,
1932
+ athletica lululemon
1933
+ athletica-lululemon
1934
+ ationincome
1935
+ ativan
1936
+ atomoxetine
1937
+ atorvastatin
1938
+ attraction marketing
1939
+ attraction-marketing
1940
+ australia boot
1941
+ australia out
1942
+ australia-boot
1943
+ australiaboot
1944
+ australian pokie
1945
+ australian-pokie
1946
+ auteur:nike
1947
+ authentic cheap
1948
+ authentic hermes
1949
+ authentic-cheap
1950
+ authentic-ugg
1951
+ authentichermes
1952
+ authenticugg
1953
+ authored subject
1954
+ authored-subject
1955
+ autoclinics.co.
1956
+ autocom
1957
+ automatic-pay
1958
+ automaticbackup.
1959
+ automaticpay
1960
+ autre artic
1961
+ autre-artic
1962
+ avatar-live
1963
+ avvessorie
1964
+ avvessory
1965
+ awokehim
1966
+ awordpress.
1967
+ azria outlet
1968
+ azria-outlet
1969
+ azur-lv
1970
+ ɑlivе
1971
+ b.u.y
1972
+ b54.in
1973
+ babycanread
1974
+ babyliss
1975
+ backlink
1976
+ baclofen
1977
+ bad credit
1978
+ bad-credit
1979
+ badcredit
1980
+ bag out
1981
+ bag-cheap
1982
+ bag-online
1983
+ bag-out
1984
+ bagcheap
1985
+ bagjap
1986
+ bagjp
1987
+ bagmirror
1988
+ bagonline
1989
+ bagonsale
1990
+ bagout
1991
+ bags afford
1992
+ bags online
1993
+ bags out
1994
+ bags sale
1995
+ bags uk
1996
+ bags-afford
1997
+ bags-cheap
1998
+ bags-online
1999
+ bags-out
2000
+ bagsale
2001
+ bagscheap
2002
+ bagsjap
2003
+ bagsjp
2004
+ bagsonline
2005
+ bagsout
2006
+ bagssale
2007
+ bagsstore
2008
+ bagstore
2009
+ bagsuk
2010
+ bailey ugg
2011
+ bailey-ugg
2012
+ baileyugg
2013
+ bajardepeso
2014
+ balance espana
2015
+ balance españa
2016
+ balenciagasingapore
2017
+ bally store
2018
+ bally-store
2019
+ ballystore
2020
+ ban baratas
2021
+ ban jacket
2022
+ ban occhiali
2023
+ ban online
2024
+ ban sunglass
2025
+ ban-baratas
2026
+ ban-jacket
2027
+ ban-occhiali
2028
+ ban-online
2029
+ ban-sunglass
2030
+ bancshare
2031
+ bangkok cosplay
2032
+ bangkok-cosplay
2033
+ bangkokcosplay
2034
+ banjacket
2035
+ bankbybank
2036
+ bankowoz
2037
+ bankrobber
2038
+ banonline
2039
+ bansunglass
2040
+ baratas-new
2041
+ baratasnewera
2042
+ baratos-new
2043
+ baratosnewera
2044
+ barbour cloth
2045
+ barbour jacket
2046
+ barbour outlet
2047
+ barbour-cloth
2048
+ barbour-jacket
2049
+ barbour-outlet
2050
+ barbourcloth
2051
+ barbourjacket
2052
+ barbouroutlet
2053
+ basket isabel
2054
+ basket-isabel
2055
+ basketisabel
2056
+ bat-pro
2057
+ bayswater bag
2058
+ bayswater-bag
2059
+ bazargorj
2060
+ bazookaapp
2061
+ bbombr
2062
+ bcbg dress
2063
+ bcbg-dress
2064
+ bddv
2065
+ be benefited
2066
+ beamten
2067
+ beanies1
2068
+ bears hat
2069
+ bears urlacher
2070
+ bears-hat
2071
+ bears-urlacher
2072
+ bearsurlacher
2073
+ beatbydre
2074
+ beats by
2075
+ beats monster
2076
+ beats pas
2077
+ beats studio
2078
+ beats-by
2079
+ beats-dr-dre
2080
+ beats-dre
2081
+ beats-monster
2082
+ beats-pas
2083
+ beats-studio
2084
+ beats+by
2085
+ beatsbydrdre
2086
+ beatsbydre
2087
+ beatscustom
2088
+ beatsdrdre
2089
+ beatsdre
2090
+ beatsmonster
2091
+ beatsstudio
2092
+ beaut beaut
2093
+ beaut bio
2094
+ beaut-beaut
2095
+ beaut-bio
2096
+ beautiful-wom
2097
+ beautifulwom
2098
+ bee-pollen.
2099
+ beeday
2100
+ beenpaid
2101
+ before-purchas
2102
+ behaviour-driven
2103
+ behind-knee
2104
+ behindknee
2105
+ beijing-escort
2106
+ beijing-massage
2107
+ beijingescort
2108
+ beijingmassage
2109
+ belize propert
2110
+ belize-propert
2111
+ belizepropert
2112
+ belly-fat
2113
+ belstaff bota
2114
+ belstaff chaqueta
2115
+ belstaff cuero
2116
+ belstaff espa
2117
+ belstaff españa
2118
+ belstaff handbag
2119
+ belstaff leder
2120
+ belstaff out
2121
+ belstaff-bota
2122
+ belstaff-chaqueta
2123
+ belstaff-cuero
2124
+ belstaff-espa
2125
+ belstaff-españa
2126
+ belstaff-handbag
2127
+ belstaff-leder
2128
+ belstaff-out
2129
+ belstaffbota
2130
+ belstaffchaqueta
2131
+ belstaffcuero
2132
+ belstaffespa
2133
+ belstaffespaña
2134
+ belstaffhandbag
2135
+ belstaffleder
2136
+ belstaffoutlet
2137
+ belt replica
2138
+ belt-replica
2139
+ beltreplica
2140
+ bengals merch
2141
+ bengals store
2142
+ bengals-merch
2143
+ bengals-store
2144
+ bengalsmerch
2145
+ bengalsstore
2146
+ benzoclin
2147
+ benzogenerator
2148
+ benzoylmethyl
2149
+ berlinmoncler
2150
+ berracom.ph
2151
+ best cyber
2152
+ best jersey
2153
+ best online
2154
+ best pant
2155
+ best tummy
2156
+ best website
2157
+ best-cyber
2158
+ best-diet
2159
+ best-direct
2160
+ best-discount
2161
+ best-fake
2162
+ best-home-cinema
2163
+ best-jersey
2164
+ best-pant
2165
+ best-phone
2166
+ best-software-for
2167
+ best-tummy
2168
+ best-way-to
2169
+ best-website
2170
+ bestad.
2171
+ bestads.
2172
+ bestcase
2173
+ bestcontractor
2174
+ bestdirect
2175
+ bestdiscount
2176
+ bestdrug
2177
+ bestfake
2178
+ bestfit
2179
+ bestjersey
2180
+ bestlaptop
2181
+ bestpant
2182
+ bestphone
2183
+ bestsuppl
2184
+ besttummy
2185
+ bestwebsite
2186
+ betlist
2187
+ betterjudg
2188
+ biaxin
2189
+ bieding laarzen
2190
+ bieding-laarzen
2191
+ biedinglaarzen
2192
+ bielizna
2193
+ big bling
2194
+ big-bling
2195
+ big-cock
2196
+ big-replica
2197
+ big-site
2198
+ big.site
2199
+ bigbling
2200
+ bigcock
2201
+ bigreplica
2202
+ billig
2203
+ binaires http
2204
+ bio bronz
2205
+ bio-bronz
2206
+ bird hack
2207
+ bird-hack
2208
+ birkenstock boston
2209
+ birkenstock online
2210
+ birkenstock-boston
2211
+ birkenstock-online
2212
+ birkenstockboston
2213
+ birkenstockonline
2214
+ birkenstockonsale
2215
+ birkenstocksandal
2216
+ birkenstockshop
2217
+ birkin bag
2218
+ birkin-bag
2219
+ birkinbag
2220
+ bisapp
2221
+ bit.ly
2222
+ bitartrate
2223
+ biuro-solido
2224
+ biz.pl
2225
+ biz.ru
2226
+ biznes
2227
+ bizstore
2228
+ biztalk
2229
+ biztout
2230
+ biżuteria
2231
+ black tight
2232
+ black ugg
2233
+ black-tight
2234
+ black-ugg
2235
+ black-www
2236
+ blackhat
2237
+ blackjack
2238
+ blacklabelj
2239
+ blacktight
2240
+ blackugg
2241
+ blanc pen
2242
+ blanc-pen
2243
+ blank http
2244
+ blazer-chaussure
2245
+ blazerchaussure
2246
+ blog beast
2247
+ blog here
2248
+ blog occasion
2249
+ blog platform
2250
+ blog soon
2251
+ blog video
2252
+ blog_
2253
+ blog-beast
2254
+ blog-here
2255
+ blog-occasion
2256
+ blog-platform
2257
+ blog-soon
2258
+ blog-trick
2259
+ blog-video
2260
+ blog-view
2261
+ blog/blog
2262
+ blog/comment
2263
+ blog/index
2264
+ blog/online
2265
+ blog/owner
2266
+ blog/post
2267
+ blog/view
2268
+ blog<
2269
+ blogbeast
2270
+ blogentry.
2271
+ bloghome
2272
+ blogid
2273
+ blogów
2274
+ blogplatform
2275
+ blogs-trick
2276
+ blogs.blog
2277
+ blogs/entry
2278
+ blogs/item
2279
+ blogs/post
2280
+ blogsoon
2281
+ blogtitle
2282
+ blowjob
2283
+ blue ugg
2284
+ blue-ugg
2285
+ bluehostreview
2286
+ bluetooth-jammer
2287
+ bluetoothheadset
2288
+ bluetoothjammer
2289
+ blueugg
2290
+ boaby
2291
+ bobet link
2292
+ bobet-link
2293
+ bodacious
2294
+ bodog8
2295
+ bonocasino
2296
+ bonus-code
2297
+ bonuscode
2298
+ book-ot-
2299
+ bookmark webpage
2300
+ bookmark-webpage
2301
+ bookmarked!
2302
+ boost-your
2303
+ boostyour
2304
+ boot online
2305
+ boot sale
2306
+ boot uk
2307
+ boot-get
2308
+ boot-online
2309
+ boot-queen
2310
+ boot-sale
2311
+ boot-uk
2312
+ bootcojp
2313
+ bootget
2314
+ bootonline
2315
+ bootqueen
2316
+ boots online
2317
+ boots sale
2318
+ boots ugg
2319
+ boots uk
2320
+ boots-get
2321
+ boots-online
2322
+ boots-queen
2323
+ boots-retail
2324
+ boots-sale
2325
+ boots-ugg
2326
+ boots-uk
2327
+ bootsale
2328
+ bootsget
2329
+ bootsonline
2330
+ bootsqueen
2331
+ bootsretail
2332
+ bootss
2333
+ bootssale
2334
+ bootsugg
2335
+ bootsuk
2336
+ boottenngoku
2337
+ bootugg
2338
+ bootuk
2339
+ borsa moncler
2340
+ borsa-moncler
2341
+ borsamoncler
2342
+ borse moncler
2343
+ borse-moncler
2344
+ borsemoncler
2345
+ boss.de
2346
+ botanical slim
2347
+ botanical-slim
2348
+ botasdefutbol
2349
+ bottes pas
2350
+ bottes ugg
2351
+ bottes-pas
2352
+ bottes-ugg
2353
+ bottespas
2354
+ bottesugg
2355
+ boutique balenciaga
2356
+ boutique chaussures
2357
+ boutique ugg
2358
+ boutique-balenciaga
2359
+ boutique-chaussures
2360
+ boutique-ugg
2361
+ boutiquechaussures
2362
+ boutiques ugg
2363
+ boutiques-ugg
2364
+ boutiquesugg
2365
+ boutiqueugg
2366
+ bow ugg
2367
+ bow-ugg
2368
+ bowugg
2369
+ boychik casino
2370
+ boychik-casino
2371
+ bracelet-sale
2372
+ braceletsale
2373
+ brain abundance
2374
+ brain-abundance
2375
+ brainabundance
2376
+ brand baseball
2377
+ brand bat
2378
+ brand engage
2379
+ brand mlb
2380
+ brand nba
2381
+ brand nhl
2382
+ brand-baseball
2383
+ brand-bat
2384
+ brand-corner
2385
+ brand-engage
2386
+ brand-jp
2387
+ brand-mlb
2388
+ brand-nba
2389
+ brand-nhl
2390
+ brandengage
2391
+ brandjp
2392
+ brandnames
2393
+ brandpurse
2394
+ bravemed
2395
+ braves jersey
2396
+ braves-jersey
2397
+ bravesjersey
2398
+ brazil bikini
2399
+ brazil-bikini
2400
+ brazilbikini
2401
+ brazzer
2402
+ breastactive
2403
+ bridal-gown
2404
+ bridalgown
2405
+ bridalshop
2406
+ brinkjewel
2407
+ britanniahotel
2408
+ brittany-battle
2409
+ brittanybattle
2410
+ brittny-battle
2411
+ brittnybattle
2412
+ broncos hat
2413
+ broncos-hat
2414
+ broncos-jersey
2415
+ broncos-official
2416
+ broncoshat
2417
+ broncosjersey
2418
+ broncosofficial
2419
+ brrip
2420
+ brugte mulberry
2421
+ brugte-mulberry
2422
+ bruiseviolet
2423
+ bruno cabas
2424
+ bruno-cabas
2425
+ brunocabas
2426
+ btn-phone
2427
+ btshoe
2428
+ buddie
2429
+ buddreview
2430
+ bukmacher
2431
+ bullion-account
2432
+ bumpant
2433
+ burberry bag
2434
+ burberry belt
2435
+ burberry borse
2436
+ burberry brit
2437
+ burberry clearance
2438
+ burberry coat
2439
+ burberry danmark
2440
+ burberry factory
2441
+ burberry lad
2442
+ burberry negozi
2443
+ burberry out
2444
+ burberry purse
2445
+ burberry sale
2446
+ burberry scarf
2447
+ burberry store
2448
+ burberry tasker
2449
+ burberry thai
2450
+ burberry uk
2451
+ burberry wallet
2452
+ burberry watch
2453
+ burberry-au
2454
+ burberry-belt
2455
+ burberry-borse
2456
+ burberry-brit
2457
+ burberry-clearance
2458
+ burberry-coat
2459
+ burberry-danmark
2460
+ burberry-hand
2461
+ burberry-lad
2462
+ burberry-negozi
2463
+ burberry-out
2464
+ burberry-purse
2465
+ burberry-sale
2466
+ burberry-scarf
2467
+ burberry-tasker
2468
+ burberry-wallet
2469
+ burberry-watch
2470
+ burberry.blog
2471
+ burberryau
2472
+ burberrybelt
2473
+ burberrybi
2474
+ burberryblack
2475
+ burberryborse
2476
+ burberrybrit
2477
+ burberryclearance
2478
+ burberrycoat
2479
+ burberrydanmark
2480
+ burberryhand
2481
+ burberrylad
2482
+ burberrynegozi
2483
+ burberryout
2484
+ burberrypurse
2485
+ burberrysale
2486
+ burberryscarf
2487
+ burberrysold
2488
+ burberrystore
2489
+ burberrysuto
2490
+ burberrytaschen
2491
+ burberrytasker
2492
+ burberrywallet
2493
+ burberrywatch
2494
+ burch-out
2495
+ burch-sale
2496
+ burchout
2497
+ burchsale
2498
+ business empire
2499
+ business-empire
2500
+ business-in
2501
+ business-loan
2502
+ business-market
2503
+ business-net
2504
+ businessboss
2505
+ businessfinder
2506
+ businessintel
2507
+ businessloan
2508
+ businessmarket
2509
+ businessnetwork
2510
+ buspirone
2511
+ busquemail
2512
+ busythumb
2513
+ butikk
2514
+ butnow
2515
+ butthe
2516
+ button ugg
2517
+ button-ugg
2518
+ buttonugg
2519
+ butwho
2520
+ buy acrylic
2521
+ buy ageless
2522
+ buy cheap
2523
+ buy fifa
2524
+ buy gig
2525
+ buy hermes
2526
+ buy insta
2527
+ buy jordan
2528
+ buy louis
2529
+ buy online
2530
+ buy private
2531
+ buy toms
2532
+ buy traffic
2533
+ buy women
2534
+ buy-acrylic
2535
+ buy-cheap
2536
+ buy-cig
2537
+ buy-fifa
2538
+ buy-gig
2539
+ buy-gucci
2540
+ buy-hair
2541
+ buy-insta
2542
+ buy-jordan
2543
+ buy-louis
2544
+ buy-movie
2545
+ buy-now
2546
+ buy-online
2547
+ buy-pill
2548
+ buy-plus
2549
+ buy-private
2550
+ buy-soma
2551
+ buy-toms
2552
+ buy-traffic
2553
+ buy-women
2554
+ buycanadagoose
2555
+ buycheap
2556
+ buycig
2557
+ buyhair
2558
+ buyhermes
2559
+ buying-facebook
2560
+ buyjap
2561
+ buyjordan
2562
+ buyjp
2563
+ buylouis
2564
+ buymovie
2565
+ buyonline
2566
+ buyplus
2567
+ buysoma
2568
+ buytoms
2569
+ buywomen
2570
+ bvlgari brand
2571
+ bvlgari store
2572
+ bvlgari-brand
2573
+ bvlgari-store
2574
+ bvlgaribrand
2575
+ bvlgarishop
2576
+ bvlgarisshop
2577
+ bvlgaristore
2578
+ by-dr-dre
2579
+ bydre-head
2580
+ bydrehead
2581
+ byo.co
2582
+ byt.es
2583
+ c.he.a.p
2584
+ c.he.ap
2585
+ c|pro
2586
+ cabas vanessa
2587
+ cabas-vanessa
2588
+ cabasvanessa
2589
+ cabin lithu
2590
+ cabin-lithu
2591
+ cabins it
2592
+ cabins lithu
2593
+ cabins-it
2594
+ cabins-lithu
2595
+ caellis
2596
+ cagoosejacket
2597
+ cagoosesale
2598
+ calabasas carpet
2599
+ calabasas rug
2600
+ calabasas-carpet
2601
+ calabasas-rug
2602
+ callgirl
2603
+ cambogia
2604
+ camgirl
2605
+ camicie abercrombie
2606
+ camicie negozi
2607
+ camicie-abercrombie
2608
+ camicie-negozi
2609
+ camicieabercrombie
2610
+ camicienegozi
2611
+ camisas ralph
2612
+ camisas-ralph
2613
+ camisasralph
2614
+ can-help-you
2615
+ canada loan
2616
+ canada-loan
2617
+ canadagoose-ca
2618
+ canadagoose-factory
2619
+ canadagoose-fr
2620
+ canadagoose-online
2621
+ canadagoose-out
2622
+ canadagooseannka
2623
+ canadagoosebanff
2624
+ canadagooseca
2625
+ canadagoosefactory
2626
+ canadagoosejack
2627
+ canadagoosemen
2628
+ canadagooseonline
2629
+ canadagooseoutlet
2630
+ canadagoosepark
2631
+ canadagooses
2632
+ canadagooses-factory
2633
+ canadagooses-out
2634
+ canadagoosesfactory
2635
+ canadagoosesoutlet
2636
+ canadaoutlet
2637
+ canadian hgh
2638
+ canadian loan
2639
+ canadian-hgh
2640
+ canadian-loan
2641
+ candycrush
2642
+ cannabis-seed
2643
+ cappelli boston
2644
+ cappelli new
2645
+ cappelli nfl
2646
+ cappelli-boston
2647
+ cappelli-new
2648
+ cappelli-nfl
2649
+ captchasnip
2650
+ card-debt
2651
+ cardy boot
2652
+ cardy-boot
2653
+ cardyboot
2654
+ care-cream
2655
+ carinsurance
2656
+ carisoprodol
2657
+ carrera bat
2658
+ carrera lunette
2659
+ carrera-bat
2660
+ carrera-lunette
2661
+ carreralunette
2662
+ carreramoinscher
2663
+ cars insurance
2664
+ cars-games
2665
+ cars-insurance
2666
+ cartuchos
2667
+ casaemail.co
2668
+ casebycase
2669
+ casesolution
2670
+ cash advance
2671
+ cash generator
2672
+ cash loan
2673
+ cash-advance
2674
+ cash-generator
2675
+ cash4gold
2676
+ cash4silver
2677
+ cashadvance
2678
+ cashforgold
2679
+ cashforsilver
2680
+ cashgenerator
2681
+ cashloan
2682
+ cashout
2683
+ casino enligne
2684
+ casino online
2685
+ casino only
2686
+ casino-enligne
2687
+ casino-game
2688
+ casino-online
2689
+ casino-only
2690
+ casino.co
2691
+ casinoenligne
2692
+ casinoer
2693
+ casinogame
2694
+ casinoonline
2695
+ casinos-
2696
+ casque beats
2697
+ casque-beats
2698
+ casquebeats
2699
+ casquette
2700
+ câsuâl
2701
+ casub.co
2702
+ catalog/preview
2703
+ catalogo/preview
2704
+ catalogs.cfm
2705
+ catalogues.cfm
2706
+ cavin-klein
2707
+ cavinklein
2708
+ ce billet
2709
+ ce-billet
2710
+ celebrex
2711
+ celebrities-nude
2712
+ celebritiesnude
2713
+ celebrity-nude
2714
+ celebritynude
2715
+ celexa
2716
+ celine bag
2717
+ celine hand
2718
+ celine luggage
2719
+ celine shop
2720
+ celine tote
2721
+ celine-bag
2722
+ celine-hand
2723
+ celine-luggage
2724
+ celine-shop
2725
+ celine-tote
2726
+ celine.gear
2727
+ celinebag
2728
+ celinehand
2729
+ celinehandbag
2730
+ celineluggage
2731
+ celineshop
2732
+ celinetote
2733
+ cellskin
2734
+ cellulitefree
2735
+ cellulitereview
2736
+ celtics color
2737
+ celtics-color
2738
+ celular
2739
+ cent|
2740
+ cgi-bin
2741
+ cgsaleca
2742
+ ch.e.ap
2743
+ ch.ea.p
2744
+ chandler baseball
2745
+ chandler-baseball
2746
+ chanel bag
2747
+ chanel handbag
2748
+ chanel out
2749
+ chanel purse
2750
+ chanel replica
2751
+ chanel sac
2752
+ chanel spring
2753
+ chanel_
2754
+ chanel--
2755
+ chanel-bag
2756
+ chanel-online
2757
+ chanel-out
2758
+ chanel-purse
2759
+ chanel-replica
2760
+ chanel-sac
2761
+ chanel-sale
2762
+ chanel-spring
2763
+ chanelbag
2764
+ chanelonline
2765
+ chaneloutlet
2766
+ chanelpurse
2767
+ chanelreplica
2768
+ chanelsac
2769
+ chanelsale
2770
+ chanelspring
2771
+ channel-operator
2772
+ chantix
2773
+ chapa shoe
2774
+ chapa-shoe
2775
+ chapashoe
2776
+ chaqueta cuero
2777
+ chaqueta oferta
2778
+ chaqueta-cuero
2779
+ chaqueta-oferta
2780
+ chaquetacuero
2781
+ chaquetaoferta
2782
+ chaquetas belstaff
2783
+ chaquetas-belstaff
2784
+ chaquetasbelstaff
2785
+ charlescave
2786
+ charms thomas
2787
+ charms-thomas
2788
+ charmsthomas
2789
+ chat-chat
2790
+ chatchat
2791
+ chaturbate
2792
+ chaussres boutique
2793
+ chaussres pascher
2794
+ chaussres-boutique
2795
+ chaussres-pascher
2796
+ chaussresboutique
2797
+ chaussrespascher
2798
+ chaussure louboutin
2799
+ chaussure paris
2800
+ chaussure_
2801
+ chaussure-asics
2802
+ chaussure-femme
2803
+ chaussure-homme
2804
+ chaussure-louboutin
2805
+ chaussure-paris
2806
+ chaussure-puma
2807
+ chaussureparis
2808
+ chaussures boutique
2809
+ chaussures christian
2810
+ chaussures femme
2811
+ chaussures louboutin
2812
+ chaussures paris
2813
+ chaussures pascher
2814
+ chaussures salomon
2815
+ chaussures ski
2816
+ chaussures sport
2817
+ chaussures ugg
2818
+ chaussures_
2819
+ chaussures- abil
2820
+ chaussures-asics
2821
+ chaussures-boutique
2822
+ chaussures-christian
2823
+ chaussures-femme
2824
+ chaussures-habil
2825
+ chaussures-homme
2826
+ chaussures-louboutin
2827
+ chaussures-paris
2828
+ chaussures-pascher
2829
+ chaussures-puma
2830
+ chaussures-salomon
2831
+ chaussures-ski
2832
+ chaussures-sport
2833
+ chaussures-ugg
2834
+ chaussuresboutique
2835
+ chaussureschristian
2836
+ chaussuresfemme
2837
+ chaussuresfr
2838
+ chaussureslouboutin
2839
+ chaussuresparis
2840
+ chaussurespascher
2841
+ chaussuressport
2842
+ chcoin.co
2843
+ cheap air
2844
+ cheap atlanta
2845
+ cheap authentic
2846
+ cheap bag
2847
+ cheap basket
2848
+ cheap beat
2849
+ cheap bike
2850
+ cheap carolina
2851
+ cheap carton
2852
+ cheap cheap
2853
+ cheap china
2854
+ cheap christian
2855
+ cheap denver
2856
+ cheap fifa
2857
+ cheap football
2858
+ cheap ga
2859
+ cheap galaxy
2860
+ cheap hockey
2861
+ cheap iphone
2862
+ cheap jersey
2863
+ cheap longchamp
2864
+ cheap louboutin
2865
+ cheap louis
2866
+ cheap mbt
2867
+ cheap michael
2868
+ cheap moncler
2869
+ cheap mont
2870
+ cheap nfl
2871
+ cheap nhl
2872
+ cheap nike
2873
+ cheap north
2874
+ cheap oakley
2875
+ cheap ray
2876
+ cheap red
2877
+ cheap sale
2878
+ cheap sherr
2879
+ cheap sunglass
2880
+ cheap supra
2881
+ cheap timberland
2882
+ cheap toms
2883
+ cheap travel
2884
+ cheap ugg
2885
+ cheap uk
2886
+ cheap wed
2887
+ cheap-adobe
2888
+ cheap-atlanta
2889
+ cheap-authentic
2890
+ cheap-bag
2891
+ cheap-basket
2892
+ cheap-beat
2893
+ cheap-bike
2894
+ cheap-carolina
2895
+ cheap-carton
2896
+ cheap-chanel
2897
+ cheap-cheap
2898
+ cheap-china
2899
+ cheap-christian
2900
+ cheap-converse
2901
+ cheap-denver
2902
+ cheap-fifa
2903
+ cheap-football
2904
+ cheap-ga
2905
+ cheap-gucci
2906
+ cheap-hat
2907
+ cheap-hermes
2908
+ cheap-hockey
2909
+ cheap-jacket
2910
+ cheap-jersey
2911
+ cheap-kobe
2912
+ cheap-louboutin
2913
+ cheap-mbt
2914
+ cheap-michael
2915
+ cheap-moncler
2916
+ cheap-mont
2917
+ cheap-nfl
2918
+ cheap-nhl
2919
+ cheap-nike
2920
+ cheap-north
2921
+ cheap-oakley
2922
+ cheap-pandora
2923
+ cheap-prada
2924
+ cheap-red
2925
+ cheap-sale
2926
+ cheap-sex
2927
+ cheap-sherr
2928
+ cheap-sunglass
2929
+ cheap-supra
2930
+ cheap-timberland
2931
+ cheap-tms
2932
+ cheap-toms
2933
+ cheap-travel
2934
+ cheap-ugg
2935
+ cheap-uk
2936
+ cheap-wed
2937
+ cheap+
2938
+ cheap<
2939
+ cheapadobe
2940
+ cheapatlanta
2941
+ cheapauthentic
2942
+ cheapbag
2943
+ cheapbasket
2944
+ cheapbeat
2945
+ cheapbeatsbydre
2946
+ cheapbike
2947
+ cheapchanel
2948
+ cheapchina
2949
+ cheapcoach
2950
+ cheapconverse
2951
+ cheapest hockey
2952
+ cheapest-hockey
2953
+ cheapest.co
2954
+ cheapesthockey
2955
+ cheapga
2956
+ cheapgucci
2957
+ cheaphat
2958
+ cheaphermes
2959
+ cheaphockey
2960
+ cheapiphone
2961
+ cheapjacket
2962
+ cheapjersey
2963
+ cheapjorda
2964
+ cheapkobe
2965
+ cheaplouboutin
2966
+ cheaplouis
2967
+ cheapmbt
2968
+ cheapmichael
2969
+ cheapmoncler
2970
+ cheapnfl
2971
+ cheapnike
2972
+ cheapnorth
2973
+ cheapoakley
2974
+ cheappandora
2975
+ cheapprada
2976
+ cheaprayban
2977
+ cheapred
2978
+ cheaps ugg
2979
+ cheaps-ugg
2980
+ cheapsale
2981
+ cheapsex
2982
+ cheapsugg
2983
+ cheapsunglass
2984
+ cheapsupra
2985
+ cheaptimberland
2986
+ cheaptms
2987
+ cheaptoms
2988
+ cheaptravel
2989
+ cheapugg
2990
+ cheapuk
2991
+ cheapweb
2992
+ cheat.co
2993
+ cheats for
2994
+ cheats-
2995
+ cheats-for
2996
+ cheats.co
2997
+ cheatsfor
2998
+ cheatss
2999
+ cheaρ
3000
+ check.asp
3001
+ check32attack
3002
+ cheesefruit
3003
+ chemise-ralph
3004
+ chemiseralph
3005
+ cher moncler
3006
+ cher prada
3007
+ cher-moncler
3008
+ cher-prada
3009
+ chermoncler
3010
+ cherprada
3011
+ chettelongchamp
3012
+ chf iraq
3013
+ chf-iraq
3014
+ chic mcm
3015
+ chic-mcm
3016
+ chicmcm
3017
+ china cheap
3018
+ china low
3019
+ china shop
3020
+ china wholesale
3021
+ china-cheap
3022
+ china-low
3023
+ china-shop
3024
+ china-wholesale
3025
+ chinacheap
3026
+ chinajorda
3027
+ chinalow
3028
+ chinawholesale
3029
+ chinska
3030
+ chlamydia
3031
+ chloe boot
3032
+ chloe sunglass
3033
+ chloe-boot
3034
+ chloe-sunglass
3035
+ chloeboot
3036
+ chloejp
3037
+ chloemoment
3038
+ chloeoutsale
3039
+ chloesunglass
3040
+ chloie
3041
+ choo sale
3042
+ choo-boots
3043
+ choo-sale
3044
+ chooboots
3045
+ chrismas.asp
3046
+ christian-louboutin
3047
+ christianlouboutin
3048
+ chrr-llc
3049
+ chung hightop
3050
+ chung-hightop
3051
+ cialis
3052
+ ciallis
3053
+ cig holder
3054
+ cig-holder
3055
+ cig-online
3056
+ cig-promo
3057
+ cig<
3058
+ cigar-cuba
3059
+ cigar-online
3060
+ cigar-store
3061
+ cigarcuba
3062
+ cigarette online
3063
+ cigarette-online
3064
+ cigarette<
3065
+ cigarettebuy
3066
+ cigarettes online
3067
+ cigarettes-online
3068
+ cigarettes<
3069
+ cigarettesbuy
3070
+ cigaronline
3071
+ cigarrette
3072
+ cigars-cuba
3073
+ cigars-online
3074
+ cigarscuba
3075
+ cigarsonline
3076
+ cigarstore
3077
+ cigbuy
3078
+ cigonline
3079
+ cigpromo
3080
+ cigs online
3081
+ cigs-online
3082
+ cigs-promo
3083
+ cigs<
3084
+ cigsbuy
3085
+ cigsonline
3086
+ cigspromo
3087
+ cinture gucci
3088
+ cinture outlet
3089
+ cinture-gucci
3090
+ cinture-outlet
3091
+ cinturegucci
3092
+ cintureoutlet
3093
+ ciproanti
3094
+ citʏ
3095
+ clans hack
3096
+ clans-hack
3097
+ clarisonic
3098
+ clash-of-clans
3099
+ clashofclans
3100
+ classic-ugg
3101
+ classicugg
3102
+ clavulanate
3103
+ clboot
3104
+ clck.ru
3105
+ cleaning calabasas
3106
+ cleaning http
3107
+ cleaning-calabasas
3108
+ clearance mbt
3109
+ clearance michael
3110
+ clearance out
3111
+ clearance sale
3112
+ clearance-mbt
3113
+ clearance-michael
3114
+ clearance-out
3115
+ clearance-sale
3116
+ clearancembt
3117
+ clearancemichael
3118
+ clearanceoutlet
3119
+ clearancesale
3120
+ clenbuterol
3121
+ clentching
3122
+ click here
3123
+ click_
3124
+ click-here
3125
+ click2
3126
+ click4
3127
+ clickbank
3128
+ clickforu
3129
+ clientarea
3130
+ climacool
3131
+ clomid
3132
+ clonazepam
3133
+ clone-key
3134
+ clonekey
3135
+ clothes online
3136
+ clothes-online
3137
+ clothesonline
3138
+ clothing abercrombie
3139
+ clothing online
3140
+ clothing-abercrombie
3141
+ clothing-online
3142
+ clothingabercrombie
3143
+ clothingonline
3144
+ clredheel
3145
+ clsale
3146
+ clshoe
3147
+ club-boy
3148
+ clubboy
3149
+ clusive vacation
3150
+ clusive-vacation
3151
+ clusivevacation
3152
+ clyel
3153
+ cms-temp
3154
+ cms-theme
3155
+ cnoesfs
3156
+ coach austr
3157
+ coach black
3158
+ coach factory
3159
+ coach flight
3160
+ coach handbag
3161
+ coach legacy
3162
+ coach out
3163
+ coach promo
3164
+ coach purse
3165
+ coach shoe
3166
+ coach sneaker
3167
+ coach thai
3168
+ coach wristlet
3169
+ coach-bag
3170
+ coach-black
3171
+ coach-factory
3172
+ coach-flight
3173
+ coach-legacy
3174
+ coach-men
3175
+ coach-new
3176
+ coach-out
3177
+ coach-promo
3178
+ coach-purse
3179
+ coach-shoe
3180
+ coach-sneaker
3181
+ coach-store
3182
+ coach-wristlet
3183
+ coach+promo
3184
+ coach+sneaker
3185
+ coach2you
3186
+ coachbag
3187
+ coachbags
3188
+ coachbay
3189
+ coachblack
3190
+ coachfactory
3191
+ coachflight
3192
+ coachhandbag
3193
+ coachja
3194
+ coachjap
3195
+ coachjp
3196
+ coachkan
3197
+ coachmise
3198
+ coachniho
3199
+ coachninnki
3200
+ coachoutlet
3201
+ coachpromo
3202
+ coachshoe
3203
+ coachsneaker
3204
+ coachstore
3205
+ coachsuto
3206
+ coachsyoppu
3207
+ coachtokyo
3208
+ coachwallet
3209
+ coachwristlet
3210
+ coachya
3211
+ code-generat
3212
+ colin-kaepernick
3213
+ collection effort
3214
+ college-loan
3215
+ collezione moncler
3216
+ collezione-moncler
3217
+ collezionemoncler
3218
+ colts hat
3219
+ colts-hat
3220
+ com http
3221
+ com.asp
3222
+ com.com
3223
+ com//
3224
+ com/author
3225
+ com/autocom
3226
+ com/bilder
3227
+ com/boards
3228
+ com/cheap
3229
+ com/css
3230
+ com/doc
3231
+ com/dress
3232
+ com/forum
3233
+ com/fr/
3234
+ com/ftp
3235
+ com/htm
3236
+ com/image
3237
+ com/include
3238
+ com/member
3239
+ com/moncler
3240
+ com/official
3241
+ com/online
3242
+ com/page1
3243
+ com/page2
3244
+ com/pharma
3245
+ com/profile
3246
+ com/public
3247
+ com/site
3248
+ com/tiffany
3249
+ com/ugg
3250
+ com/user
3251
+ com/vuitton
3252
+ com%2c
3253
+ com2.php
3254
+ comedyee
3255
+ comment-pag
3256
+ commentabout
3257
+ commented here
3258
+ commented-here
3259
+ commentsyou
3260
+ commerce retail
3261
+ commerce-retail
3262
+ community.atom
3263
+ commutee
3264
+ como ganhar
3265
+ como-ganhar
3266
+ compare price
3267
+ compare-price
3268
+ component/blog
3269
+ comprar
3270
+ computer-gaming
3271
+ computer-performance
3272
+ computerpressrelease
3273
+ computers.in
3274
+ comreview
3275
+ comunity
3276
+ conficker worm
3277
+ conficker-worm
3278
+ consalt-
3279
+ constructionn
3280
+ construtor
3281
+ contact/contact
3282
+ contactus/contact
3283
+ conversejapan
3284
+ conversejp
3285
+ conydot
3286
+ cooker-ninja
3287
+ cookerninja
3288
+ coordintaing
3289
+ copie ugg
3290
+ copie-ugg
3291
+ copieugg
3292
+ copy-wizard
3293
+ copywizard
3294
+ cordarone
3295
+ corporate-gift
3296
+ corporategift
3297
+ cort.as
3298
+ coskobo
3299
+ cosm tiques
3300
+ cosmetics-out
3301
+ cosmeticswholesale
3302
+ cosmtiques
3303
+ cost-effective
3304
+ costume ermen
3305
+ costume homme
3306
+ costume mariage
3307
+ costume marie
3308
+ costume marié
3309
+ costume tendance
3310
+ costume versace
3311
+ costume-ermen
3312
+ costume-homme
3313
+ costume-mariage
3314
+ costume-marie
3315
+ costume-marié
3316
+ costume-medieval
3317
+ costume-tendance
3318
+ costume-versace
3319
+ costumes homme
3320
+ costumes-homme
3321
+ couchey fr
3322
+ couchey-fr
3323
+ coucheyfr
3324
+ coumadin
3325
+ countrу
3326
+ couple gratuite
3327
+ couple-gratuite
3328
+ coupon_
3329
+ coupon-code
3330
+ coupon-pag
3331
+ coupon.blog
3332
+ couponcode
3333
+ coupons_
3334
+ coupons-pag
3335
+ couponsense
3336
+ courses casino
3337
+ courses-casino
3338
+ couture avec
3339
+ couture-avec
3340
+ coverages
3341
+ cozy-ugg
3342
+ cozyugg
3343
+ coսld
3344
+ cracked-pro
3345
+ crackedpro
3346
+ crane-hire
3347
+ cranehire
3348
+ create-product
3349
+ credit repair
3350
+ credit-card
3351
+ credit-report
3352
+ credit-score
3353
+ credit.eu
3354
+ creditcard.org
3355
+ creditreport
3356
+ cription.asp
3357
+ cristmas-
3358
+ crossof
3359
+ cruise vacation
3360
+ cruise-vacation
3361
+ cruisevacation
3362
+ crystalmall
3363
+ cuir vanessa
3364
+ cuir-vanessa
3365
+ cuirvanessa
3366
+ cup jersey
3367
+ cup-jersey
3368
+ cure herpes
3369
+ cure-herpes
3370
+ cure.co.
3371
+ curehelp
3372
+ cures.co.
3373
+ currency trad
3374
+ currency-trad
3375
+ custom-nike
3376
+ custom-rim
3377
+ custom-wheel
3378
+ custom+tire
3379
+ custom+wheel
3380
+ customrim
3381
+ customwheel
3382
+ cuurently
3383
+ cyber monday
3384
+ cyber-monday
3385
+ cybermonday
3386
+ cygara
3387
+ cymbalta
3388
+ cytotec
3389
+ cz/love
3390
+ cеrt
3391
+ dabloggs
3392
+ dafeult
3393
+ dailly
3394
+ daily.blog
3395
+ dailyreview.co
3396
+ dailystrength
3397
+ dakotasuki
3398
+ damen timberland
3399
+ damen-timberland
3400
+ damentimberland
3401
+ damier-azur
3402
+ damskie
3403
+ dannerjp
3404
+ dapoxetin
3405
+ dapoxetine
3406
+ darmowe ogloszenia
3407
+ darmowe ogłoszenia
3408
+ darmowe-ogloszenia
3409
+ darmowe-ogłoszenia
3410
+ darmowe-programy
3411
+ darmoweogloszenia
3412
+ darmoweogłoszenia
3413
+ darmoweprogramy
3414
+ darmowy
3415
+ darrellbox
3416
+ darrellwire
3417
+ darvocet
3418
+ data-tools
3419
+ database.co
3420
+ datarecovery.co
3421
+ datarecoveryhospital
3422
+ dataz
3423
+ dating-guide
3424
+ datingdirect
3425
+ datingguide
3426
+ datingsite
3427
+ day loan
3428
+ day-diet
3429
+ daytrade
3430
+ daytrading
3431
+ de site
3432
+ de-contacto
3433
+ de-site
3434
+ deal.blog
3435
+ dealonline
3436
+ dealsuk
3437
+ dealsus
3438
+ dealuk
3439
+ dealus
3440
+ dear-lover
3441
+ dearlover
3442
+ debt_
3443
+ debt-help
3444
+ debt-management
3445
+ debt-relief
3446
+ debt-solution
3447
+ debthelp
3448
+ debtrelief
3449
+ dedrease
3450
+ default/member
3451
+ default1
3452
+ default2
3453
+ definitelly
3454
+ delete_
3455
+ delpha_
3456
+ deltasone
3457
+ demo123
3458
+ demontag
3459
+ denschlaf
3460
+ dental-implant
3461
+ dental-quote
3462
+ depositbank
3463
+ depression-symptom
3464
+ depressionsymptom
3465
+ derm exclus
3466
+ derm-exclus
3467
+ dermexclus
3468
+ desconto
3469
+ designer bag
3470
+ designer-bag
3471
+ designer-brand
3472
+ designer-jewel
3473
+ designer-shoe
3474
+ designerbag
3475
+ designerbrand
3476
+ designerjewel
3477
+ designerlabel
3478
+ designershoe
3479
+ desktop-client
3480
+ desktopclient
3481
+ despaulsmith
3482
+ desyrel
3483
+ detail/www
3484
+ detektiv
3485
+ devenir trade
3486
+ devenir-trade
3487
+ devil1.
3488
+ devil2.
3489
+ devilspite
3490
+ dewelop
3491
+ dg-schoenen
3492
+ dg-shoe
3493
+ di droga
3494
+ di-droga
3495
+ diablo3
3496
+ diamox
3497
+ diary_
3498
+ diazepam
3499
+ diclofenac
3500
+ dienst.in
3501
+ diesel denim
3502
+ diesel hot
3503
+ diesel jean
3504
+ diesel uk
3505
+ diesel watch
3506
+ diesel-denim
3507
+ diesel-hot
3508
+ diesel-jean
3509
+ diesel-uk
3510
+ diesel-watch
3511
+ dieseldenim
3512
+ dieselhot
3513
+ dieselwatch
3514
+ diet-food
3515
+ diet-pill
3516
+ diet-plan
3517
+ diet-review
3518
+ diet-solution
3519
+ diet-suppl
3520
+ diet.co
3521
+ dietpill
3522
+ dietplan
3523
+ dietreview
3524
+ dietsolution
3525
+ dietsuppl
3526
+ differin
3527
+ diflucan
3528
+ diggs.us
3529
+ dincob
3530
+ dinner soup
3531
+ dinner-soup
3532
+ dior_
3533
+ diorkan
3534
+ direct-fund
3535
+ direct-health
3536
+ direct-lend
3537
+ direct-lone
3538
+ directhealth
3539
+ directlend
3540
+ directlone
3541
+ dirt-bike
3542
+ disclaim.asp
3543
+ discount bag
3544
+ discount jordan
3545
+ discount mbt
3546
+ discount mulberry
3547
+ discount nfl
3548
+ discount north
3549
+ discount ugg
3550
+ discount-
3551
+ discount-bag
3552
+ discount-cig
3553
+ discount-jordan
3554
+ discount-mbt
3555
+ discount-north
3556
+ discount-ugg
3557
+ discount-wheel
3558
+ discount.co
3559
+ discount.co.
3560
+ discount.org
3561
+ discountbag
3562
+ discountcig
3563
+ discounted north
3564
+ discounted-
3565
+ discounted-north
3566
+ discounted-wheel
3567
+ discountednorth
3568
+ discountedwheel
3569
+ discountmbt
3570
+ discountnorth
3571
+ discountt
3572
+ discountugg
3573
+ discountwheel
3574
+ diva-com
3575
+ divulgaemail
3576
+ djstool
3577
+ djtool
3578
+ dk http
3579
+ dlphone
3580
+ doable program
3581
+ doable-program
3582
+ doableprogram
3583
+ dobrucki.co
3584
+ dobrucki.pl
3585
+ doc/soap
3586
+ docid=
3587
+ doctermarten
3588
+ docteurdrebeat
3589
+ document_
3590
+ documents/celine
3591
+ documents/newbalance
3592
+ documents/nike
3593
+ documents/northface
3594
+ documents/rolex
3595
+ docxdrive
3596
+ does green
3597
+ does-green
3598
+ doesgreen
3599
+ doesn t
3600
+ dokumentov
3601
+ dokumentów
3602
+ dolce bag
3603
+ dolce-bag
3604
+ dolcebag
3605
+ dollar-service
3606
+ dollarservice
3607
+ dolphins jersey
3608
+ dolphins-jersey
3609
+ dolphinsjersey
3610
+ domainbie
3611
+ dominateseo
3612
+ domination-secret
3613
+ dominationsecret
3614
+ donna-donn
3615
+ donne-donn
3616
+ dos-seios
3617
+ dotcomsecret
3618
+ douchingteen
3619
+ doudoune
3620
+ downjacket
3621
+ download bracelet
3622
+ download-bracelet
3623
+ downloadbracelet
3624
+ doxycycline
3625
+ dragon avail
3626
+ dragon-avail
3627
+ dragons avail
3628
+ dragons-avail
3629
+ drayvera
3630
+ drdreheadphone
3631
+ dre beat
3632
+ dre cheap
3633
+ dre-beat
3634
+ dre-beats
3635
+ dre-cheap
3636
+ dre<
3637
+ drebeat
3638
+ drecheap
3639
+ dress link
3640
+ dress online
3641
+ dress shoe
3642
+ dress shop
3643
+ dress-link
3644
+ dress-online
3645
+ dress-shoe
3646
+ dress-shop
3647
+ dress.rent
3648
+ dresses.wed
3649
+ dresshop
3650
+ dresslink
3651
+ dressonline
3652
+ dresssale
3653
+ dressshop
3654
+ drivewayservice
3655
+ drmartensjapan
3656
+ drmartensjp
3657
+ drug-cheap
3658
+ drugcheap
3659
+ drugs-cheap
3660
+ drugscheap
3661
+ drupal-temp
3662
+ drupal-theme
3663
+ dsquared giubbotto
3664
+ dsquared jean
3665
+ dsquared online
3666
+ dsquared outlet
3667
+ dsquared shoe
3668
+ dsquared uomo
3669
+ dsquared-giubbotto
3670
+ dsquared-jean
3671
+ dsquared-online
3672
+ dsquared-outlet
3673
+ dsquared-shoe
3674
+ dsquared-uomo
3675
+ dsquaredonline
3676
+ dsquaredoutlet
3677
+ dsquaredshoe
3678
+ dubai-princess
3679
+ dubturbo
3680
+ dude.de
3681
+ dudes.de
3682
+ dummytest
3683
+ dunhill/dunhill
3684
+ dunjakke
3685
+ durant shoe
3686
+ durant-shoe
3687
+ duvetica outlet
3688
+ duvetica-outlet
3689
+ duveticaoutlet
3690
+ dvdrip
3691
+ dwi-attorney
3692
+ dwiattorney
3693
+ dylongfa
3694
+ dyubetika
3695
+ e-biz
3696
+ eâcute
3697
+ eairfix
3698
+ early-signs-of
3699
+ earthly lover
3700
+ earthly-lover
3701
+ ease.in
3702
+ easy.in
3703
+ easyloan
3704
+ easyrent
3705
+ eaudiovideo
3706
+ ebaypic
3707
+ ebook-reader-test
3708
+ ebook-test
3709
+ ebookreadertest
3710
+ ebooktest
3711
+ ecco out
3712
+ ecco-out
3713
+ eccooutlet
3714
+ ecent yeas
3715
+ ed-in-men
3716
+ eemail
3717
+ effexor
3718
+ egoodshop
3719
+ einkommen
3720
+ ejaculation-pharm
3721
+ ejaculationpharm
3722
+ el-gordo.c
3723
+ elamale
3724
+ elavil
3725
+ elite jersey
3726
+ elite model
3727
+ elite-jersey
3728
+ elite-men
3729
+ elite-model
3730
+ elitejersey
3731
+ elitemodel
3732
+ eloans
3733
+ elway-jersey
3734
+ elwayjersey
3735
+ email.htm
3736
+ email.tst
3737
+ emailsvip
3738
+ emailvip
3739
+ emarketing
3740
+ emiliopucci
3741
+ empire hack
3742
+ empire-hack
3743
+ empirehack
3744
+ empower network
3745
+ empower-network
3746
+ empowernetwork
3747
+ en/formula
3748
+ en/oakley
3749
+ endlaved
3750
+ eneugh
3751
+ eng/faq
3752
+ enhance-your
3753
+ enhancement-pill
3754
+ enhancementpill
3755
+ enjoy-more
3756
+ enourmous
3757
+ entry_
3758
+ entrykey
3759
+ entryview.asp
3760
+ envisionforce
3761
+ eomarketplace
3762
+ ephedra
3763
+ ephedrine
3764
+ epica watch
3765
+ epica-watch
3766
+ epo doping
3767
+ eqbandz
3768
+ equipment-manufactur
3769
+ era mlb
3770
+ era nba
3771
+ era nhl
3772
+ era uk
3773
+ era-mlb
3774
+ era-nba
3775
+ era-nfl
3776
+ era-nhl
3777
+ era-uk
3778
+ erectile
3779
+ erettile
3780
+ erjersey.co
3781
+ erjersey.net
3782
+ erolove
3783
+ erotic toy
3784
+ erotic-toy
3785
+ erotictoy
3786
+ erotik
3787
+ erotyczna
3788
+ errу
3789
+ es.iodress
3790
+ es/content
3791
+ escitalopram
3792
+ escort-zone
3793
+ escorts.
3794
+ escortss
3795
+ escortzone
3796
+ eshop.co
3797
+ essay-empire
3798
+ essay-service
3799
+ essayempire
3800
+ essays-empire
3801
+ essays-service
3802
+ essaysempire
3803
+ essayservice
3804
+ essaysservice
3805
+ estate pro
3806
+ estate whether
3807
+ estate-pro
3808
+ estate-whether
3809
+ estatepro
3810
+ estradiol
3811
+ etherdq
3812
+ euro-million
3813
+ euroditalog
3814
+ europe nfl
3815
+ eurovids
3816
+ evelyne bag
3817
+ evelyne-bag
3818
+ evelynebag
3819
+ event_
3820
+ eventid
3821
+ every advertise
3822
+ every1bet
3823
+ everythink
3824
+ evryday
3825
+ evеr
3826
+ exboyfriend
3827
+ excelent
3828
+ excellent blog
3829
+ excellent site
3830
+ excellent website
3831
+ excellent-blog
3832
+ excellent-site
3833
+ excellent-website
3834
+ excellentlunch
3835
+ exclusive rendez
3836
+ exclusive-rendez
3837
+ exclusive.ru
3838
+ executive search
3839
+ executive-search
3840
+ exelon
3841
+ exercice
3842
+ exgirlfriend
3843
+ exit.asp
3844
+ expensive vacation
3845
+ expensive-vacation
3846
+ expensivevacation
3847
+ expert suggestion
3848
+ expert-suggestion
3849
+ explosive growth
3850
+ explosive-growth
3851
+ express index
3852
+ express-index
3853
+ expressindex
3854
+ extra gry
3855
+ extreme-sport
3856
+ extremely}
3857
+ eyeglass sale
3858
+ eyeglass-sale
3859
+ eyeglasses sale
3860
+ eyeglasses-sale
3861
+ eyeglasssale
3862
+ eyеs
3863
+ eѕcort
3864
+ eхperienc
3865
+ fa‡on
3866
+ faar more
3867
+ faar-more
3868
+ fabulous drug
3869
+ fabulous-drug
3870
+ fabulousdrug
3871
+ face denali
3872
+ face jacket
3873
+ face out
3874
+ face sale
3875
+ face store
3876
+ face terra
3877
+ face vest
3878
+ face women
3879
+ face-denali
3880
+ face-jacket
3881
+ face-out
3882
+ face-sale
3883
+ face-store
3884
+ face-terra
3885
+ face-vest
3886
+ face-women
3887
+ facebok
3888
+ facebook advert
3889
+ facebook cash
3890
+ facebook class
3891
+ facebook-ads
3892
+ facebook-advert
3893
+ facebook-cash
3894
+ facebook-class
3895
+ facebook-fan
3896
+ facebook-traffic
3897
+ facebookads
3898
+ facebookadvert
3899
+ facebookcash
3900
+ facebookclass
3901
+ facebookfan
3902
+ facebooklike
3903
+ facebooku
3904
+ facejacket
3905
+ faceoutlet
3906
+ facesale
3907
+ facestore
3908
+ faceterra
3909
+ facevest
3910
+ facialhair
3911
+ factory outlet
3912
+ factory-out
3913
+ factory-outlet
3914
+ facts-about
3915
+ fagance
3916
+ fajki
3917
+ fajna strona
3918
+ fajna-fotka
3919
+ fajna-strona
3920
+ fajnafotka
3921
+ fajnastrona
3922
+ fajne
3923
+ fake mirror
3924
+ fake oakley
3925
+ fake rayban
3926
+ fake sunglass
3927
+ fake-converse
3928
+ fake-mirror
3929
+ fake-oakley
3930
+ fake-rayban
3931
+ fake-sunglass
3932
+ fakeconverse
3933
+ fakeoakley
3934
+ fakeok
3935
+ fakerayban
3936
+ fakesunglass
3937
+ falsedoc
3938
+ falsepassport
3939
+ fanshome
3940
+ fantastic blog
3941
+ fantastic-blog
3942
+ farmacias
3943
+ farming-secrets
3944
+ farmingsecrets
3945
+ fashion list
3946
+ fashion store
3947
+ fashion-boot
3948
+ fashion-bracelet
3949
+ fashion-class
3950
+ fashion-list
3951
+ fashion-store
3952
+ fashionboot
3953
+ fashionbracelet
3954
+ fashionistblog
3955
+ fast-loan
3956
+ fast|quick
3957
+ fastcash
3958
+ fastidious data
3959
+ fastidious thought
3960
+ fastidious urg
3961
+ fastidious-data
3962
+ fastidious-thought
3963
+ fastidious-urg
3964
+ fastloan
3965
+ fat loss
3966
+ fat men
3967
+ fat quite
3968
+ fat women
3969
+ fat-burn
3970
+ fat-loss
3971
+ fat-men
3972
+ fat-quite
3973
+ fat-women
3974
+ fatburn
3975
+ fatloss
3976
+ favorite website
3977
+ fb-ads
3978
+ fb-cash
3979
+ fb-traffic
3980
+ fbads
3981
+ fbcash
3982
+ fbfans
3983
+ fblike
3984
+ fckt
3985
+ fcukfcuk
3986
+ features.cfm
3987
+ federl
3988
+ feelng
3989
+ feichang0
3990
+ feihuang0
3991
+ felpe hollister
3992
+ felpe moncler
3993
+ felpe-hollister
3994
+ felpe-moncler
3995
+ felpemoncler
3996
+ female handbag
3997
+ female-handbag
3998
+ femalehandbag
3999
+ females handbag
4000
+ females-handbag
4001
+ femaleshandbag
4002
+ femme chaussure
4003
+ femme-chaussure
4004
+ femme-sac
4005
+ femmechaussure
4006
+ femmes-canada-goose
4007
+ femmesac
4008
+ femmescanadagoose
4009
+ fendi belt
4010
+ fendi-belt
4011
+ fendi1
4012
+ fendi2
4013
+ fendibelt
4014
+ fenoma
4015
+ fenteetum
4016
+ ferra-gamo
4017
+ ferragamo sale
4018
+ ferragamo tie
4019
+ ferragamo-sale
4020
+ ferragamo-tie
4021
+ ferragamolove
4022
+ ferragamosale
4023
+ ferragamoshop
4024
+ ferragamotie
4025
+ fg xpress
4026
+ fg-xpress
4027
+ fgxpress
4028
+ fibromyalgia
4029
+ fifa ultimate
4030
+ fifa-ultimate
4031
+ fifaultimate
4032
+ fightmark
4033
+ filenamedat
4034
+ filenamesdat
4035
+ filestube
4036
+ film porn
4037
+ film porno
4038
+ film x
4039
+ film-porn
4040
+ film-porno
4041
+ film-x
4042
+ filmizle
4043
+ films porn
4044
+ films x
4045
+ films-porn
4046
+ films-x
4047
+ finance-
4048
+ finance-blog
4049
+ financial debt
4050
+ financial_
4051
+ financial-debt
4052
+ financial-emergency
4053
+ financial-service
4054
+ financialservice
4055
+ finanse
4056
+ finansowanie
4057
+ finasteride
4058
+ find-the-answer
4059
+ findarticle
4060
+ findmewom
4061
+ fine wives
4062
+ fine-wives
4063
+ finewives
4064
+ fioricet
4065
+ firefox-setting
4066
+ firefoxik.ru
4067
+ firefoxsetting
4068
+ firm.ru
4069
+ firma.php
4070
+ fitch gilet
4071
+ fitch outlet
4072
+ fitch-gilet
4073
+ fitch-outlet
4074
+ fitchgilet
4075
+ fitchoutlet
4076
+ fitflop
4077
+ fivestardoll
4078
+ fix-credit
4079
+ fixcredit
4080
+ fixing-credit
4081
+ fixingcredit
4082
+ fjrm
4083
+ flagyl
4084
+ flappy-bird
4085
+ flappybird
4086
+ flats.webeden
4087
+ flexglobal
4088
+ flik.us
4089
+ flixya
4090
+ floridaflee
4091
+ floxacin
4092
+ fluccun
4093
+ fluconazole
4094
+ fluoxetine
4095
+ fluticasone
4096
+ fobur.in
4097
+ foodpyramid
4098
+ foolproof trick
4099
+ foolproof-trick
4100
+ foot nike
4101
+ foot-nike
4102
+ football shirt
4103
+ football-shirt
4104
+ footdiscount
4105
+ footwear jordan
4106
+ footwear mbt
4107
+ footwear-jordan
4108
+ footwear-mbt
4109
+ footwearmbt
4110
+ footwears
4111
+ for cheap
4112
+ for gucci
4113
+ for-cheap
4114
+ for-gucci
4115
+ for-interactive
4116
+ for-men
4117
+ for-money
4118
+ for-the-most
4119
+ for-windows-8
4120
+ for-your-need
4121
+ for+sale
4122
+ for|
4123
+ forboots
4124
+ forcheap
4125
+ forex
4126
+ forfree
4127
+ forgucci
4128
+ forhandlere
4129
+ forjp.co
4130
+ formaldress
4131
+ formula replica
4132
+ formula-replica
4133
+ forsale-japan
4134
+ forsalego
4135
+ forsalejapan
4136
+ forsales
4137
+ forthcoming post
4138
+ forthcoming-post
4139
+ forum coach
4140
+ forum-coach
4141
+ forum.asp
4142
+ forum.php
4143
+ forum/1/topic
4144
+ forum/ftopic
4145
+ forum/member
4146
+ forum/post
4147
+ forum/topic
4148
+ forum/user
4149
+ forums?func
4150
+ forums/1/topic
4151
+ forums/member
4152
+ forums/topic
4153
+ forums/user
4154
+ forwindows8
4155
+ foryou.co
4156
+ forzest
4157
+ fr canad
4158
+ fr-canad
4159
+ fr.fr/
4160
+ fr/acheter
4161
+ fr/botte
4162
+ fr/canad
4163
+ fr/costume
4164
+ fr/longchamp
4165
+ fr/pascher
4166
+ fradidas
4167
+ frames/index
4168
+ francemaillot
4169
+ fraudcenter
4170
+ frauen puma
4171
+ frauen-puma
4172
+ frauenpuma
4173
+ free class
4174
+ free gay
4175
+ free international
4176
+ free prescript
4177
+ free visitor
4178
+ free web
4179
+ free-bbs
4180
+ free-bid
4181
+ free-brows
4182
+ free-casino
4183
+ free-class
4184
+ free-gay
4185
+ free-international
4186
+ free-ipad
4187
+ free-iphone
4188
+ free-ipod
4189
+ free-mods
4190
+ free-movie
4191
+ free-offer
4192
+ free-online
4193
+ free-poker
4194
+ free-prescript
4195
+ free-program
4196
+ free-web
4197
+ free-website
4198
+ free.in
4199
+ freearticle
4200
+ freebbs
4201
+ freebid
4202
+ freebrows
4203
+ freecasino
4204
+ freeclass
4205
+ freedating
4206
+ freefor.co
4207
+ freegay
4208
+ freehub
4209
+ freeinternational
4210
+ freeipad
4211
+ freeiphone
4212
+ freeipod
4213
+ freembtrans
4214
+ freemovie
4215
+ freeoffer
4216
+ freeonline
4217
+ freepoker
4218
+ freesale
4219
+ freesalg
4220
+ freesimcard
4221
+ freeslotmachine
4222
+ freevideo
4223
+ freeweb
4224
+ freewebsite
4225
+ french escort
4226
+ french-escort
4227
+ frenchescort
4228
+ fresh review
4229
+ fresh-review
4230
+ freshreview
4231
+ freshwaterpearl
4232
+ friday moncler
4233
+ friday sale
4234
+ friday ugg
4235
+ friday-moncler
4236
+ friday-sale
4237
+ friday-ugg
4238
+ fridaymoncler
4239
+ fridaysale
4240
+ fridayugg
4241
+ frlongchamp
4242
+ frmoncler
4243
+ frontline commando
4244
+ frontline-commando
4245
+ fruitful design
4246
+ fruitful-design
4247
+ fruta planta
4248
+ frutaplanta
4249
+ fuckdown
4250
+ func.php
4251
+ fund http
4252
+ fund market
4253
+ fund trend
4254
+ fund-market
4255
+ fund-trend
4256
+ fundmarket
4257
+ funds.ru
4258
+ funsneak
4259
+ funwithwindows
4260
+ fur boot
4261
+ fur-boot
4262
+ furboot
4263
+ furiousguy
4264
+ furla bag
4265
+ furla candy
4266
+ furla handbag
4267
+ furla out
4268
+ furla-bag
4269
+ furla-candy
4270
+ furla-handbag
4271
+ furla-out
4272
+ furlahandbag
4273
+ furlasacs
4274
+ furnituresale
4275
+ furosemide
4276
+ furworld.ru
4277
+ futbol barcelona
4278
+ futbol-barcelona
4279
+ futbolbarcelona
4280
+ futuristic-market
4281
+ futuristicmarket
4282
+ f眉r
4283
+ g-string
4284
+ gaaab.co
4285
+ gabapentin
4286
+ gabbana store
4287
+ gabbana-cheap
4288
+ gabbana-shop
4289
+ gabbana-store
4290
+ gabbanacheap
4291
+ gabbanashop
4292
+ gabbanastore
4293
+ gafas ray
4294
+ gafas-ray
4295
+ gafasray
4296
+ gaga-japan
4297
+ gaga-jp
4298
+ gaga-milano
4299
+ gagner
4300
+ gain weight
4301
+ gain-weight
4302
+ gainweight
4303
+ galaxynail
4304
+ gallergrind
4305
+ gambling online
4306
+ gambling-online
4307
+ gamblingonline
4308
+ game wiki
4309
+ game-casino
4310
+ game-copy
4311
+ game-jersey
4312
+ game-wiki
4313
+ gamecopy
4314
+ gamedesigndegree
4315
+ gamegame
4316
+ games-casino
4317
+ gamewiki
4318
+ gamma blue
4319
+ gamma-blue
4320
+ gammablue
4321
+ gamyba
4322
+ gangprofil
4323
+ ganhar dinheiro
4324
+ ganhar-dinheiro
4325
+ gaogb
4326
+ gapscent
4327
+ garcinia
4328
+ gawab.com
4329
+ gay sex
4330
+ gay-sex
4331
+ gaysex
4332
+ gayusa
4333
+ gelatine free
4334
+ gelatine-free
4335
+ gemorroya
4336
+ genemy
4337
+ general/genera
4338
+ generate cash
4339
+ generate money
4340
+ generate-cash
4341
+ generate-money
4342
+ generatecash
4343
+ generatemoney
4344
+ generating cash
4345
+ generating money
4346
+ generating-cash
4347
+ generating-money
4348
+ generatingcash
4349
+ generatingmoney
4350
+ generation algorithm
4351
+ generation-algorithm
4352
+ generator-2014
4353
+ generator2014
4354
+ generatorpro
4355
+ genuine-pandora
4356
+ genuinely fast
4357
+ genuinely fruit
4358
+ genuinely-fast
4359
+ genuinely-fruit
4360
+ genuinepandora
4361
+ germany jersey
4362
+ germany-jersey
4363
+ germanylove
4364
+ gestione
4365
+ get_rid_of
4366
+ get-boot
4367
+ get-facebook
4368
+ get-hermes
4369
+ get-massive
4370
+ get-money-for
4371
+ get-rid-of
4372
+ get-the-answer
4373
+ getaloan
4374
+ getastyle
4375
+ gethermes
4376
+ getjoy
4377
+ getmassive
4378
+ getridof
4379
+ getting-men
4380
+ gettranslate
4381
+ getyou.asp
4382
+ gfband
4383
+ ghd gold
4384
+ ghd straight
4385
+ ghd-gold
4386
+ ghd-pascher
4387
+ ghd-straight
4388
+ ghdgold
4389
+ ghdpascher
4390
+ ghdstraight
4391
+ ghduk
4392
+ giants-shop
4393
+ giantsjersey
4394
+ giantsshop
4395
+ gifts-singapore
4396
+ giftsingapore
4397
+ giftssingapore
4398
+ gigantix.co
4399
+ gilet moncler
4400
+ gilet-moncler
4401
+ giletmoncler
4402
+ girl escort
4403
+ girl jordan
4404
+ girl-day-dress
4405
+ girl-escort
4406
+ girl-jordan
4407
+ girl-jp
4408
+ girldaydress
4409
+ girlescort
4410
+ girlie spouse
4411
+ girlie-spouse
4412
+ girliespouse
4413
+ girljordan
4414
+ girljp
4415
+ girls escort
4416
+ girls-day-dress
4417
+ girls-escort
4418
+ girlsdaydress
4419
+ girlsescort
4420
+ giubbotti woolrich
4421
+ giubbotti-woolrich
4422
+ giubbotto dsquared
4423
+ giubbotto-dsquared
4424
+ giuseppezanotti
4425
+ gkhk
4426
+ glamorousbag
4427
+ glasses-tokyo
4428
+ glassess
4429
+ glassestokyo
4430
+ gleevec
4431
+ glitter ugg
4432
+ glitter-ugg
4433
+ glitterugg
4434
+ global-agenda
4435
+ globalagenda
4436
+ globalist-agenda
4437
+ globalistagenda
4438
+ globalnpn
4439
+ glucophage
4440
+ glutamina
4441
+ glyburide
4442
+ gmaiil
4443
+ gneuienly
4444
+ gnlaser
4445
+ goedkoop
4446
+ gointeractive.co
4447
+ gojp.co
4448
+ gold-account
4449
+ gold-coin
4450
+ gold-earring
4451
+ gold-essay
4452
+ gold-ingot
4453
+ gold-jewelry
4454
+ gold-price
4455
+ gold-seiko
4456
+ gold.ru
4457
+ goldbarren
4458
+ goldcoin
4459
+ goldendoll
4460
+ goldessay
4461
+ goldgeek
4462
+ goldingot
4463
+ goldjewelry
4464
+ goldseiko
4465
+ goldsuppl
4466
+ goldtruth
4467
+ golf-promo
4468
+ golf-shop
4469
+ golfplaza
4470
+ golfpromo
4471
+ golfs
4472
+ gomaile.co
4473
+ goo.gl
4474
+ good article
4475
+ good blog
4476
+ good-article
4477
+ good-blog
4478
+ good-for-
4479
+ good-game
4480
+ good}
4481
+ goodbye.asp
4482
+ goodgame
4483
+ goodnessknows
4484
+ goodsblog
4485
+ google http
4486
+ google_
4487
+ google-java
4488
+ googlebind
4489
+ googleing
4490
+ googleusashop
4491
+ goose chill
4492
+ goose coat
4493
+ goose enfant
4494
+ goose expedition
4495
+ goose femme
4496
+ goose grise
4497
+ goose herre
4498
+ goose homme
4499
+ goose ital
4500
+ goose jacka
4501
+ goose jacke
4502
+ goose jakke
4503
+ goose jas
4504
+ goose norge
4505
+ goose online
4506
+ goose out
4507
+ goose paris
4508
+ goose parka
4509
+ goose pas
4510
+ goose retail
4511
+ goose sale
4512
+ goose v
4513
+ goose yorkville
4514
+ goose youth
4515
+ goose-canad
4516
+ goose-coat
4517
+ goose-enfant
4518
+ goose-expedition
4519
+ goose-femme
4520
+ goose-grise
4521
+ goose-herre
4522
+ goose-homme
4523
+ goose-ital
4524
+ goose-jacka
4525
+ goose-jacke
4526
+ goose-jakke
4527
+ goose-jas
4528
+ goose-norge
4529
+ goose-online
4530
+ goose-out
4531
+ goose-paris
4532
+ goose-parka
4533
+ goose-pas
4534
+ goose-retail
4535
+ goose-sale
4536
+ goose-v
4537
+ goose-vest
4538
+ goose-yorkville
4539
+ goose-youth
4540
+ goose<
4541
+ gooseca
4542
+ goosecanad
4543
+ goosecheap
4544
+ goosecoat
4545
+ goosedk
4546
+ gooseenfant
4547
+ gooseexpedition
4548
+ goosefemme
4549
+ goosegrise
4550
+ gooseherre
4551
+ goosehomme
4552
+ gooseital
4553
+ goosejacka
4554
+ goosejacke
4555
+ goosejakke
4556
+ goosejas
4557
+ goosenorge
4558
+ gooseonline
4559
+ gooseoutlet
4560
+ gooseparis
4561
+ gooseparka
4562
+ goosepas
4563
+ gooseretail
4564
+ goosesale
4565
+ goosescheap
4566
+ gooseshop
4567
+ goosevest
4568
+ gooseyorkville
4569
+ gooseyouth
4570
+ gorgeous escort
4571
+ gorgeous-escort
4572
+ gorgeousescort
4573
+ gosgov
4574
+ goshop.
4575
+ gotowkowa
4576
+ gotowkowe
4577
+ gown-love
4578
+ gownlove
4579
+ gowns-love
4580
+ gownslove
4581
+ goyard-bag
4582
+ goyard-online
4583
+ goyardbag
4584
+ goyardonline
4585
+ graduand
4586
+ gratuit http
4587
+ gratuit roulette
4588
+ gratuit-roulette
4589
+ gratuite http
4590
+ gratuitos
4591
+ graypanther
4592
+ grayson bag
4593
+ grayson-bag
4594
+ great article
4595
+ great blog
4596
+ great goods
4597
+ great written
4598
+ great-article
4599
+ great-blog
4600
+ great-essay
4601
+ great-goods
4602
+ great-things
4603
+ great-written
4604
+ great}
4605
+ greatbet
4606
+ greece-holid
4607
+ greeceholid
4608
+ green-smoker
4609
+ greensmoker
4610
+ greеce
4611
+ grise parka
4612
+ grise-parka
4613
+ griseofulvin
4614
+ griseparka
4615
+ grooming needs
4616
+ grooming-needs
4617
+ grossrx
4618
+ group_
4619
+ group-home
4620
+ group-review
4621
+ grow-cannabis
4622
+ growmens
4623
+ growth hormone
4624
+ growth-hormone
4625
+ growthhormone
4626
+ gruppmeddelanden
4627
+ gruzowe
4628
+ gruzu
4629
+ gry flesh
4630
+ gry online
4631
+ guarantee_
4632
+ guarantee-uptime
4633
+ guaranteed_
4634
+ guaranteed-uptime
4635
+ gucchi
4636
+ gucci bag
4637
+ gucci brief
4638
+ gucci discount
4639
+ gucci envy
4640
+ gucci factory
4641
+ gucci gucci
4642
+ gucci guilt
4643
+ gucci handbag
4644
+ gucci italia
4645
+ gucci online
4646
+ gucci out
4647
+ gucci sale
4648
+ gucci seller
4649
+ gucci time
4650
+ gucci vintage
4651
+ gucci_
4652
+ gucci--
4653
+ gucci-bag
4654
+ gucci-brief
4655
+ gucci-discount
4656
+ gucci-envy
4657
+ gucci-factory
4658
+ gucci-glass
4659
+ gucci-gucci
4660
+ gucci-guilt
4661
+ gucci-handbag
4662
+ gucci-italia
4663
+ gucci-online
4664
+ gucci-out
4665
+ gucci-purse
4666
+ gucci-replica
4667
+ gucci-sale
4668
+ gucci-seller
4669
+ gucci-time
4670
+ gucci-uk
4671
+ gucci-vintage
4672
+ gucci-you
4673
+ gucci2
4674
+ guccibag
4675
+ gucciden
4676
+ guccidiscount
4677
+ guccienvy
4678
+ guccifactory
4679
+ guccifr
4680
+ gucciglass
4681
+ guccigucci
4682
+ gucciguilt
4683
+ guccihandbag
4684
+ gucciinstock
4685
+ gucciitalia
4686
+ gucciiuk
4687
+ guccij
4688
+ guccikan
4689
+ guccinose
4690
+ guccionline
4691
+ guccioutlet
4692
+ gucciparis
4693
+ guccipurse
4694
+ guccireplica
4695
+ guccisale
4696
+ gucciseller
4697
+ guccisingapore
4698
+ gucciten
4699
+ guccitime
4700
+ gucciuk
4701
+ guccivintage
4702
+ gucciyu
4703
+ guerre gratuit
4704
+ guerre http
4705
+ guerre-gratuit
4706
+ guest-post
4707
+ guestpost
4708
+ guiltfree
4709
+ guru1
4710
+ gurus1
4711
+ gyslera
4712
+ g眉nstig
4713
+ habitof
4714
+ hack facebook
4715
+ hack fb
4716
+ hack-facebook
4717
+ hack-fb
4718
+ hack<
4719
+ hackasphalt
4720
+ hackfacebook
4721
+ hackfb
4722
+ hadheard
4723
+ hair-again
4724
+ hair-grow
4725
+ hair-remov
4726
+ hair-straight
4727
+ hairagain
4728
+ hairgrow
4729
+ hairmodel
4730
+ hairremov
4731
+ hairstraight
4732
+ hamilton norge
4733
+ hamilton-norge
4734
+ handbag distrib
4735
+ handbag louis
4736
+ handbag out
4737
+ handbag sale
4738
+ handbag store
4739
+ handbag uk
4740
+ handbag wholesale
4741
+ handbag wom
4742
+ handbag-distrib
4743
+ handbag-for
4744
+ handbag-louis
4745
+ handbag-out
4746
+ handbag-sale
4747
+ handbag-store
4748
+ handbag-wholesale
4749
+ handbag-wom
4750
+ handbag+
4751
+ handbagdistrib
4752
+ handbagfor
4753
+ handbaglouis
4754
+ handbagout
4755
+ handbags distrib
4756
+ handbags louis
4757
+ handbags out
4758
+ handbags store
4759
+ handbags uk
4760
+ handbags wholesale
4761
+ handbags wom
4762
+ handbags-distrib
4763
+ handbags-for
4764
+ handbags-louis
4765
+ handbags-out
4766
+ handbags-store
4767
+ handbags-wholesale
4768
+ handbags-wom
4769
+ handbagsale
4770
+ handbagsdistrib
4771
+ handbagsfor
4772
+ handbagslouis
4773
+ handbagsout
4774
+ handbagssale
4775
+ handbagsstore
4776
+ handbagstore
4777
+ handbagsu
4778
+ handbagswholesale
4779
+ handbagswom
4780
+ handbagu
4781
+ handbagwholesale
4782
+ handbagwom
4783
+ hanging-with-friends
4784
+ hangingwithfriends
4785
+ haohao
4786
+ hardtool
4787
+ harnessedthem
4788
+ has cuisine
4789
+ has-cuisine
4790
+ hats carolina
4791
+ hats chicago
4792
+ hats denver
4793
+ hats indiana
4794
+ hats oakland
4795
+ hats-carolina
4796
+ hats-chicago
4797
+ hats-cincin
4798
+ hats-denver
4799
+ hats-indiana
4800
+ hats-new
4801
+ hats-oakland
4802
+ hatschicago
4803
+ hatsdenver
4804
+ hatsindiana
4805
+ hatsnap
4806
+ hatsoakland
4807
+ hatssnap
4808
+ hautschez
4809
+ haveasite
4810
+ havegive
4811
+ havegone
4812
+ hawksjersey
4813
+ hcg-boost
4814
+ hcgboost
4815
+ headset2012
4816
+ headset2013
4817
+ headset2014
4818
+ healthhow
4819
+ hedge fund
4820
+ hedge-fund
4821
+ heel_pads
4822
+ heelped
4823
+ heil hitler
4824
+ heil-hitler
4825
+ heilhitler
4826
+ hellllo
4827
+ helllo
4828
+ hello-sex
4829
+ hellodress
4830
+ hellosex
4831
+ help_you
4832
+ help-tax
4833
+ helpcry
4834
+ helpful-information
4835
+ helpful-method
4836
+ helplink.asp
4837
+ hemorroide
4838
+ hence choose
4839
+ hentai
4840
+ herbal tincture
4841
+ herbal-medicin
4842
+ herbal-smoking
4843
+ herbal-tincture
4844
+ herbalmedicin
4845
+ herbalsmoking
4846
+ herbaltincture
4847
+ hermes austr
4848
+ hermes bag
4849
+ hermes belt
4850
+ hermes couch
4851
+ hermes evelyne
4852
+ hermes factory
4853
+ hermes handbag
4854
+ hermes official
4855
+ hermes out
4856
+ hermes scarve
4857
+ hermes store
4858
+ hermes uk
4859
+ hermes wallet
4860
+ hermes xl
4861
+ hermes-bag
4862
+ hermes-belt
4863
+ hermes-couch
4864
+ hermes-discount
4865
+ hermes-evelyne
4866
+ hermes-factory
4867
+ hermes-official
4868
+ hermes-out
4869
+ hermes-replica
4870
+ hermes-store
4871
+ hermes-uk
4872
+ hermes-wallet
4873
+ hermes-xl
4874
+ hermesbag
4875
+ hermesbelt
4876
+ hermescouch
4877
+ hermesdiscount
4878
+ hermesevelyne
4879
+ hermesfactory
4880
+ hermeshut
4881
+ hermesofficial
4882
+ hermesout
4883
+ hermesreplica
4884
+ hermesstore
4885
+ hermesuk
4886
+ hermeswallet
4887
+ hermesxl
4888
+ hernia support
4889
+ hernia surgery
4890
+ hernia-support
4891
+ hernia-surgery
4892
+ herpes infect
4893
+ herpes treatment
4894
+ herpes-infect
4895
+ herpes-treatment
4896
+ herpes<
4897
+ herren moncler
4898
+ herren timberland
4899
+ herren-moncler
4900
+ herren-timberland
4901
+ herrenmoncler
4902
+ herrentimberland
4903
+ heuer-new
4904
+ hfg.cc
4905
+ hfgfh
4906
+ hgfj
4907
+ hggh
4908
+ hgh
4909
+ hgh dopa
4910
+ hgh enhance
4911
+ hgh natural
4912
+ hgh purchase
4913
+ hgh-dopa
4914
+ hgh-enhance
4915
+ hgh-natural
4916
+ hgh-purchase
4917
+ hgh-sup
4918
+ hgher
4919
+ hghsup
4920
+ hid_
4921
+ hierbasmedicin
4922
+ high-heel
4923
+ high-profile
4924
+ high-protein
4925
+ high.cc
4926
+ highbloodpressure
4927
+ highprofile
4928
+ highprotein
4929
+ hingenieur
4930
+ hisslipper
4931
+ hitfit
4932
+ hjblog
4933
+ hleepd
4934
+ hndeds
4935
+ hogan online
4936
+ hogan out
4937
+ hogan scarpe
4938
+ hogan shoe
4939
+ hogan sito
4940
+ hogan-online
4941
+ hogan-out
4942
+ hogan-scarpe
4943
+ hogan-shoe
4944
+ hogan-sito
4945
+ hoganoutlet
4946
+ hoganshoe
4947
+ hogansito
4948
+ holdinga
4949
+ holdning
4950
+ hollister brasil
4951
+ hollister jean
4952
+ hollister lederjacke
4953
+ hollister nantes
4954
+ hollister online
4955
+ hollister pas
4956
+ hollister roma
4957
+ hollister shirt
4958
+ hollister short
4959
+ hollister sverige
4960
+ hollister swim
4961
+ hollister uk
4962
+ hollister-brasil
4963
+ hollister-deutsch
4964
+ hollister-jean
4965
+ hollister-lederjacke
4966
+ hollister-milano
4967
+ hollister-nantes
4968
+ hollister-online
4969
+ hollister-pas
4970
+ hollister-roma
4971
+ hollister-shirt
4972
+ hollister-short
4973
+ hollister-sverige
4974
+ hollister-swim
4975
+ hollister-uk
4976
+ hollisterbrasil
4977
+ hollisterdeutsch
4978
+ hollistermilano
4979
+ hollisternantes
4980
+ hollisteronline
4981
+ hollistershirt
4982
+ hollistersverige
4983
+ hollisterswim
4984
+ hollisteruk
4985
+ home-based
4986
+ home-loan
4987
+ home-remed
4988
+ homebased
4989
+ homeforsale
4990
+ homeloan
4991
+ homeremed
4992
+ homesforsale
4993
+ homme giorgio
4994
+ homme hugo
4995
+ homme solde
4996
+ homme-giorgio
4997
+ homme-hugo
4998
+ homme-solde
4999
+ hoodia
5000
+ hoodie-cheap
5001
+ hoodiecheap
5002
+ hoody-cheap
5003
+ hoodycheap
5004
+ hoolgain
5005
+ hoolz
5006
+ horoscopes
5007
+ horoskop
5008
+ horsesimul
5009
+ host.ro
5010
+ hosting community
5011
+ hosting-community
5012
+ hot tech
5013
+ hot_babe
5014
+ hot-babe
5015
+ hot-girl
5016
+ hot-love
5017
+ hot-pantie
5018
+ hot-panty
5019
+ hot-sale
5020
+ hot-tag
5021
+ hot-tags
5022
+ hot-tech
5023
+ hot.htm
5024
+ hotburberry
5025
+ hotel deal
5026
+ hotel hermes
5027
+ hotel-deal
5028
+ hotel-hermes
5029
+ hotelbritannia
5030
+ hoteldeal
5031
+ hotelhermes
5032
+ hoteli
5033
+ hotelmanchester
5034
+ hotgirl
5035
+ hotlove
5036
+ hotpantie
5037
+ hotpanty
5038
+ hotsale
5039
+ hotsunglass
5040
+ hottag
5041
+ hottest tech
5042
+ hottest update
5043
+ hottest-tech
5044
+ hottest-update
5045
+ hourpayday
5046
+ houseforsale
5047
+ housesforsale
5048
+ how_do_
5049
+ how-do-you
5050
+ how-to-buy
5051
+ how-to-clean
5052
+ how-to-creat
5053
+ how-to-get
5054
+ how-to-have
5055
+ how-to-lose
5056
+ how-to-make
5057
+ how-to-medi
5058
+ how-to-quick
5059
+ how-to-reduc
5060
+ how-to-restor
5061
+ how-to-sell
5062
+ how-to-speed
5063
+ how-to-take
5064
+ how-to-teach
5065
+ how-to-unlock
5066
+ how-to-win
5067
+ howtobuy
5068
+ howtocreat
5069
+ howtocure
5070
+ howtomake
5071
+ howtomedi
5072
+ howtoreg
5073
+ howtospeed
5074
+ howtounlock
5075
+ howtowin
5076
+ hppp
5077
+ hqsteroid
5078
+ htaccrss
5079
+ html-article
5080
+ htmllink
5081
+ htmlnew
5082
+ huay-today
5083
+ huaytoday
5084
+ hugescock
5085
+ hungurian
5086
+ huntingtexas
5087
+ huntingtx
5088
+ huperzine
5089
+ hyclate
5090
+ hydraulik-
5091
+ hydrocodone
5092
+ hydrotherapy
5093
+ hydroxatone
5094
+ hydroxy
5095
+ hyper-fb
5096
+ hyper-link
5097
+ hyperlink
5098
+ hypothyroidism
5099
+ hyzaar
5100
+ i aint
5101
+ i-aint
5102
+ i-will-be
5103
+ �
5104
+ i2g
5105
+ ia€?ll
5106
+ iamimports
5107
+ icon/set
5108
+ icons/set
5109
+ idanmark
5110
+ ideea
5111
+ ifyou
5112
+ im not
5113
+ im-not
5114
+ image-old
5115
+ image/cache
5116
+ image/image
5117
+ image/index
5118
+ image/old
5119
+ image/table
5120
+ image/ugg
5121
+ images-old
5122
+ images/cache
5123
+ images/celine
5124
+ images/image
5125
+ images/index
5126
+ images/newbalance
5127
+ images/nike
5128
+ images/northface
5129
+ images/old
5130
+ images/rolex
5131
+ images/smilies
5132
+ images/table
5133
+ images/ugg
5134
+ imalook
5135
+ imitation hermes
5136
+ imitaugg
5137
+ imitrex
5138
+ immediate income
5139
+ immediate-income
5140
+ immediateincome
5141
+ immediatey
5142
+ immobilier lux
5143
+ immobilier-lux
5144
+ immobilierlux
5145
+ implanty
5146
+ impregnacji
5147
+ impressive share
5148
+ impressive-share
5149
+ in-disguise
5150
+ inbeing
5151
+ inbto
5152
+ include priceless
5153
+ includes priceless
5154
+ income.in
5155
+ increase traffic
5156
+ increase-traffic
5157
+ increasetraffic
5158
+ incredible article
5159
+ incredible-article
5160
+ inderal
5161
+ indeutsch
5162
+ index/css
5163
+ indexold
5164
+ indicators.co
5165
+ inetry
5166
+ infected almost
5167
+ infected-almost
5168
+ infinity-2
5169
+ infinity2
5170
+ info/product
5171
+ info/tag
5172
+ info/user
5173
+ info/view
5174
+ infolist
5175
+ infonetcom
5176
+ informasjon.htm
5177
+ informatik
5178
+ informatique enligne
5179
+ informatique-enligne
5180
+ informative blog
5181
+ informative post
5182
+ informative web
5183
+ informative-blog
5184
+ informative-web
5185
+ infos-
5186
+ infos/
5187
+ infusionsoft
5188
+ infеcted crash
5189
+ infеcted-crash
5190
+ ington boot
5191
+ ington-boot
5192
+ ingtonboot
5193
+ ingugg
5194
+ inheritance cash
5195
+ inheritance-cash
5196
+ initiator_
5197
+ injectionfacts
5198
+ injury-lawyer
5199
+ injurylawyer
5200
+ insanejournal
5201
+ insanity workout
5202
+ insanity-workout
5203
+ insanity.php
5204
+ insanityworkout
5205
+ insdier
5206
+ insomnia tip
5207
+ insomnia-tip
5208
+ inspired-handbag
5209
+ inspiredhandbag
5210
+ instafab
5211
+ install-virtual
5212
+ installvirtual
5213
+ instant loan
5214
+ instant traffic
5215
+ instant web
5216
+ instant-blog
5217
+ instant-loan
5218
+ instantblog
5219
+ instantcash
5220
+ instantloan
5221
+ instantpay
5222
+ instantweekly
5223
+ instructor car
5224
+ instructor-car
5225
+ insurance car
5226
+ insurance-car
5227
+ insurance-compan
5228
+ insurance-quote
5229
+ insurances
5230
+ intagra
5231
+ intdrnation
5232
+ interesting blog
5233
+ interesting-blog
5234
+ interferende
5235
+ internet gambling
5236
+ internet lifestyle
5237
+ internet link
5238
+ internet pag
5239
+ internet poker
5240
+ internet site
5241
+ internet website
5242
+ internet-gambling
5243
+ internet-lifestyle
5244
+ internet-link
5245
+ internet-market
5246
+ internet-poker
5247
+ internet-site
5248
+ internet-website
5249
+ internet.in
5250
+ internetgambling
5251
+ internetowej
5252
+ internetpoker
5253
+ interracial
5254
+ intersting
5255
+ invest-money
5256
+ invest-off
5257
+ invest.net
5258
+ invest/stock
5259
+ investing/stock
5260
+ investing+
5261
+ investinwell
5262
+ investir
5263
+ investmoney
5264
+ investoff
5265
+ investor.ru
5266
+ inzest
5267
+ ip.idealhosting.net.tr
5268
+ ipad-2-case
5269
+ ipad-download
5270
+ ipad-repair
5271
+ ipad-suppl
5272
+ ipad2me
5273
+ ipad2you
5274
+ ipadrepair
5275
+ ipadsuppl
5276
+ iphone-crack
5277
+ iphone-repair
5278
+ iphone-suppl
5279
+ iphone/iphone
5280
+ iphone2me
5281
+ iphone2you
5282
+ iphone4case
5283
+ iphone4scase
5284
+ iphonecase
5285
+ iphonecrack
5286
+ iphonerepair
5287
+ iphonesuppl
5288
+ ipod-repair
5289
+ ipod-suppl
5290
+ ipodrepair
5291
+ ipodsuppl
5292
+ iprofit
5293
+ irc-chat
5294
+ is seo
5295
+ is-now-available
5296
+ is.gd
5297
+ isabel marant
5298
+ isabel-marant
5299
+ isabelmarant
5300
+ island jacket
5301
+ island-jacket
5302
+ islandjacket
5303
+ isotretinoine
5304
+ isseo
5305
+ istanbul escort
5306
+ istanbul-escort
5307
+ istanbulescort
5308
+ it rite
5309
+ it-rite
5310
+ italia scarpe
5311
+ italia-scarpe
5312
+ italiascarpe
5313
+ italy-shop
5314
+ italy-store
5315
+ italyshop
5316
+ italystore
5317
+ itemnotfound
5318
+ itstree
5319
+
5320
+ jacken-online
5321
+ jackenonline
5322
+ jackenwest
5323
+ jacket canad
5324
+ jacket sale
5325
+ jacket-canad
5326
+ jacket-jp
5327
+ jacket-sale
5328
+ jacketcanad
5329
+ jackets sale
5330
+ jackets-for-kids
5331
+ jackets-for-men
5332
+ jackets-for-wom
5333
+ jackets-jp
5334
+ jackets-sale
5335
+ jackets2012
5336
+ jackets2013
5337
+ jackets2014
5338
+ jacketsale
5339
+ jacketsforkids
5340
+ jacketsformen
5341
+ jacketsforwom
5342
+ jacketssale
5343
+ jacketswom
5344
+ jagowho
5345
+ jam jordan
5346
+ jam-jordan
5347
+ japan-1
5348
+ japanconverse
5349
+ japandrmartens
5350
+ japaneseconverse
5351
+ japanesedrmartens
5352
+ japanesemarcjacobs
5353
+ japanesemontblanc
5354
+ japaneseswarovski
5355
+ japanmarcjacobs
5356
+ japanmonster
5357
+ japanmontblanc
5358
+ japannew
5359
+ japanonline
5360
+ japanswarovski
5361
+ jassen dames
5362
+ jassen outlet
5363
+ jassen-dames
5364
+ jassen-outlet
5365
+ jassendames
5366
+ jassenoutlet
5367
+ jcshoe
5368
+ jeacoma.co
5369
+ jean taste
5370
+ jean-taste
5371
+ jeans good
5372
+ jeans taste
5373
+ jeans-taste
5374
+ jeanstaste
5375
+ jeantaste
5376
+ jeremy scott
5377
+ jeremy-scott
5378
+ jeremyads
5379
+ jeremyscott
5380
+ jeremyscottwing
5381
+ jersetblack
5382
+ jersey cheap
5383
+ jersey from
5384
+ jersey wholesale
5385
+ jersey-2013
5386
+ jersey-2014
5387
+ jersey-cheap
5388
+ jersey-from
5389
+ jersey-pro
5390
+ jersey-wholesale
5391
+ jersey.htm
5392
+ jersey.us
5393
+ jersey+
5394
+ jersey2013
5395
+ jersey2014
5396
+ jerseycheap
5397
+ jerseyfrom
5398
+ jerseyonline
5399
+ jerseypro
5400
+ jerseyred
5401
+ jerseys cheap
5402
+ jerseys from
5403
+ jerseys wholesale
5404
+ jerseys-4-you
5405
+ jerseys-cheap
5406
+ jerseys-for-you
5407
+ jerseys-from
5408
+ jerseys-wholesale
5409
+ jerseys.us
5410
+ jerseys4you
5411
+ jerseyscheap
5412
+ jerseysforyou
5413
+ jerseysfrom
5414
+ jerseysusa
5415
+ jerseyswholesale
5416
+ jerseyusa
5417
+ jerseywhite
5418
+ jerseywholesale
5419
+ jewelery
5420
+ jeweline.
5421
+ jewellery.blog
5422
+ jewelry collect
5423
+ jewelry expens
5424
+ jewelry-collect
5425
+ jewelry-expens
5426
+ jewelry<
5427
+ jewelrybest
5428
+ jewelrycollect
5429
+ jewelryexpens
5430
+ jimmy-choo
5431
+ jimmychoo
5432
+ jjl
5433
+ joggingstroll
5434
+ jogos
5435
+ john-varvatos
5436
+ joint-pain
5437
+ jointpain
5438
+ jordan 1
5439
+ jordan 11
5440
+ jordan basket
5441
+ jordan brand
5442
+ jordan femme
5443
+ jordan gamma
5444
+ jordan out
5445
+ jordan pas
5446
+ jordan retro
5447
+ jordan shoe
5448
+ jordan store
5449
+ jordan-1
5450
+ jordan-11
5451
+ jordan-basket
5452
+ jordan-brand
5453
+ jordan-femme
5454
+ jordan-gamma
5455
+ jordan-pas
5456
+ jordan-retro
5457
+ jordan-sale
5458
+ jordan-shoe
5459
+ jordan-store
5460
+ jordan1
5461
+ jordanbrand
5462
+ jordangamma
5463
+ jordankicks
5464
+ jordanretro
5465
+ jordans cheap
5466
+ jordans-cheap
5467
+ jordansale
5468
+ jordanscheap
5469
+ jordanshoe
5470
+ jordansshoe
5471
+ jordanstore
5472
+ jordjev
5473
+ journal/item
5474
+ jp-bag
5475
+ jp-best
5476
+ jp-sale
5477
+ jp/blog
5478
+ jpbag
5479
+ jpbest
5480
+ jpcity.co
5481
+ jpconverse
5482
+ jpmarcjacob
5483
+ jpmonster
5484
+ jpsale
5485
+ jpsasics
5486
+ js wing
5487
+ js-wing
5488
+ jsadidas
5489
+ jswing
5490
+ juanjuan
5491
+ juicycouture
5492
+ jumpedup
5493
+ justcloud
5494
+ justness
5495
+ kaepernick jersey
5496
+ kaepernick wom
5497
+ kaepernick youth
5498
+ kaepernick-jersey
5499
+ kaepernick-wom
5500
+ kaepernick-youth
5501
+ kaepernickjersey
5502
+ kaepernickwom
5503
+ kaepernickyouth
5504
+ kaffee-maschine
5505
+ kaffeemaschine
5506
+ kamagra
5507
+ kameri
5508
+ kanalizacyjne
5509
+ kanyewestsun
5510
+ kardashian
5511
+ karenmillen-au
5512
+ karenmillenau
5513
+ karpaczwsieci
5514
+ karuteie
5515
+ kasino
5516
+ katalog
5517
+ katespadese
5518
+ kensington parka
5519
+ kensington-parka
5520
+ kensingtonparka
5521
+ key-programmer
5522
+ keygen
5523
+ keylessremote
5524
+ keyword.txt
5525
+ keywords1
5526
+ kfcnfl
5527
+ khumbu north
5528
+ khumbu-north
5529
+ kids nike
5530
+ kids out
5531
+ kids ugg
5532
+ kids-nike
5533
+ kids-ugg
5534
+ kidsnike
5535
+ kino-online
5536
+ kinoonline
5537
+ kitai
5538
+ kitchen-worktop
5539
+ kitchenworktop
5540
+ kleding winkel
5541
+ kleding-winkel
5542
+ kledingwinkel
5543
+ klonopin
5544
+ klub.ru
5545
+ knee-joint
5546
+ knee-pain
5547
+ kneejoint
5548
+ kneepain
5549
+ knicely
5550
+ knigki
5551
+ knigko
5552
+ knockoff eyewear
5553
+ knockoff-eyewear
5554
+ knockoff-handbag
5555
+ knockoffhandbag
5556
+ knolckoff
5557
+ knowledgeable individual
5558
+ knowledgeable-individual
5559
+ known blog
5560
+ known-blog
5561
+ kobe-shoe
5562
+ kobeshoe
5563
+ komputer
5564
+ komputery
5565
+ konkurs
5566
+ konsultan-
5567
+ kontakta-oss
5568
+ kontrahenta
5569
+ koop dsquared
5570
+ koop-dsquared
5571
+ koopdsquared
5572
+ koopsted
5573
+ kopfhoerer
5574
+ kopia-zapasowa
5575
+ kor outlet
5576
+ kor-outlet
5577
+ koroutlet
5578
+ kors austr
5579
+ kors bag
5580
+ kors brasil
5581
+ kors canad
5582
+ kors charlton
5583
+ kors cheap
5584
+ kors dillard
5585
+ kors factory
5586
+ kors france
5587
+ kors glass
5588
+ kors grayson
5589
+ kors hamilton
5590
+ kors handbag
5591
+ kors laptop
5592
+ kors milano
5593
+ kors out
5594
+ kors outlet
5595
+ kors puffer
5596
+ kors purse
5597
+ kors replica
5598
+ kors runway
5599
+ kors tonne
5600
+ kors uk
5601
+ kors vancouver
5602
+ kors wallet
5603
+ kors-bag
5604
+ kors-bags
5605
+ kors-canad
5606
+ kors-charlton
5607
+ kors-cheap
5608
+ kors-dillard
5609
+ kors-factory
5610
+ kors-glass
5611
+ kors-grayson
5612
+ kors-hamilton
5613
+ kors-handbag
5614
+ kors-laptop
5615
+ kors-milano
5616
+ kors-out
5617
+ kors-outlet
5618
+ kors-puffer
5619
+ kors-purse
5620
+ kors-tonne
5621
+ kors-vancouver
5622
+ kors-watch
5623
+ korsbag
5624
+ korscanad
5625
+ korsglass
5626
+ korshandbag
5627
+ korslaptop
5628
+ korsout
5629
+ korsoutlet
5630
+ korspurse
5631
+ korswatch
5632
+ kosmetyc
5633
+ kosmetyki
5634
+ kosze
5635
+ kreddyt
5636
+ kreddyyt
5637
+ kredit
5638
+ kredyt
5639
+ ku42.
5640
+ kvartiry
5641
+ k眉nst
5642
+ l.uk.e.w.a.rm
5643
+ l'argent
5644
+ l’argent
5645
+ laarzen kopen
5646
+ laarzen-kopen
5647
+ laarzenkopen
5648
+ labetalol
5649
+ lacoste-out
5650
+ lacosteout
5651
+ lamictal
5652
+ lamisil
5653
+ lancel pas
5654
+ lancel sac
5655
+ lancel-pas
5656
+ lancel-sac
5657
+ lancelad
5658
+ laplap
5659
+ large tote
5660
+ large-tote
5661
+ largetote
5662
+ lariam
5663
+ las|
5664
+ lasart.es
5665
+ laser-therapy
5666
+ lasercuttingmachine
5667
+ laseriv
5668
+ laserowe
5669
+ lasertherapy
5670
+ lasix
5671
+ latonya.
5672
+ lauren amsterdam
5673
+ lauren cheap
5674
+ lauren dame
5675
+ lauren factory
5676
+ lauren heren
5677
+ lauren home
5678
+ lauren homme
5679
+ lauren kleding
5680
+ lauren neder
5681
+ lauren norge
5682
+ lauren online
5683
+ lauren oslo
5684
+ lauren out
5685
+ lauren polo
5686
+ lauren ralph
5687
+ lauren sale
5688
+ lauren sverige
5689
+ lauren uk
5690
+ lauren-amsterdam
5691
+ lauren-austr
5692
+ lauren-cheap
5693
+ lauren-dame
5694
+ lauren-factory
5695
+ lauren-heren
5696
+ lauren-home
5697
+ lauren-homme
5698
+ lauren-kleding
5699
+ lauren-neder
5700
+ lauren-norge
5701
+ lauren-online
5702
+ lauren-oslo
5703
+ lauren-out
5704
+ lauren-polo
5705
+ lauren-ralph
5706
+ lauren-sale
5707
+ lauren-sverige
5708
+ lauren-uk
5709
+ laurenaustr
5710
+ laurencheap
5711
+ laurendame
5712
+ laurenhome
5713
+ laurenhomme
5714
+ laurennorge
5715
+ laurenonline
5716
+ laurenout
5717
+ laurenpolo
5718
+ laurenralph
5719
+ laurensale
5720
+ laurensverige
5721
+ laurent femme
5722
+ laurent sandal
5723
+ laurent-femme
5724
+ laurent-sandal
5725
+ laurentfemme
5726
+ laurenuk
5727
+ lawoffice.net
5728
+ lead-system
5729
+ leaked1
5730
+ learn facebook
5731
+ learn-facebook
5732
+ learn-helpful
5733
+ learnfacebook
5734
+ learningxchange
5735
+ learnpianohere
5736
+ leather-levi
5737
+ leatherlevi
5738
+ lebronshoe
5739
+ lebronxshoe
5740
+ led_display
5741
+ led_down
5742
+ led_flood
5743
+ led_indust
5744
+ led_street
5745
+ leder-jacken
5746
+ lederjacken
5747
+ leg-wear
5748
+ legal cash
5749
+ legal-cash
5750
+ legal-steroid
5751
+ legalbud
5752
+ legalsteroid
5753
+ legends hack
5754
+ legends-hack
5755
+ leger band
5756
+ leger-band
5757
+ legerband
5758
+ lend-direct
5759
+ lenddirect
5760
+ lendsomemoney
5761
+ lenjerie
5762
+ lesben-
5763
+ lesbos.
5764
+ lespaulsmith
5765
+ lesson1
5766
+ letrozole
5767
+ levaquin
5768
+ level 50
5769
+ level market
5770
+ level-50
5771
+ level-market
5772
+ levelmarket
5773
+ levitra
5774
+ levne
5775
+ liabaleles
5776
+ libraries.cfm
5777
+ library.cfm
5778
+ librarys.cfm
5779
+ librium
5780
+ lifeinsurance
5781
+ lifelock
5782
+ ligne http
5783
+ likе
5784
+ limited jersey
5785
+ limited-jersey
5786
+ limitedjersey
5787
+ limo-service
5788
+ linguim.co
5789
+ link http
5790
+ link issue
5791
+ link_
5792
+ link-bait
5793
+ link-build
5794
+ link-campaign
5795
+ link-issue
5796
+ link-juice
5797
+ link-market
5798
+ link-pyramid
5799
+ link-serv
5800
+ link-track
5801
+ link-vault
5802
+ linkbait
5803
+ linkbuild
5804
+ linkcampaign
5805
+ linking issue
5806
+ linking_
5807
+ linking-campaign
5808
+ linking-issue
5809
+ linking-market
5810
+ linking-serv
5811
+ linkingcampaign
5812
+ linkiseo
5813
+ linklegend
5814
+ linkman
5815
+ links http
5816
+ linktrack
5817
+ linkusup
5818
+ linkvault
5819
+ linkz
5820
+ lionsfan
5821
+ lionsjersey
5822
+ lipitor
5823
+ lisinopril
5824
+ lisseur-pascher
5825
+ lisseurpascher
5826
+ listajp
5827
+ listasegment
5828
+ litte more
5829
+ litte-more
5830
+ live-article
5831
+ livearticle
5832
+ livesex
5833
+ llifted
5834
+ loan canad
5835
+ loan compan
5836
+ loan fast
5837
+ loan http
5838
+ loan online
5839
+ loan-canad
5840
+ loan-compan
5841
+ loan-direct
5842
+ loan-fast
5843
+ loan-online
5844
+ loan.co
5845
+ loan.in
5846
+ loan.net
5847
+ loanalys
5848
+ loancompan
5849
+ loandirect
5850
+ loanfast
5851
+ loanonline
5852
+ loans canad
5853
+ loans compan
5854
+ loans fast
5855
+ loans http
5856
+ loans online
5857
+ loans-canad
5858
+ loans-compan
5859
+ loans-direct
5860
+ loans-fast
5861
+ loans-online
5862
+ loans.co
5863
+ loans.in
5864
+ loans.net
5865
+ loans1
5866
+ loans2
5867
+ loans3
5868
+ loans4
5869
+ loanscanad
5870
+ loanscompan
5871
+ loansdirect
5872
+ loansfast
5873
+ loansonline
5874
+ locate-cell-phone
5875
+ locateacellphone
5876
+ locatecellphone
5877
+ lodz
5878
+ łódź
5879
+ logcabins
5880
+ login.php
5881
+ loiusvuitton
5882
+ lol i
5883
+ london-genuine
5884
+ londongenuine
5885
+ long long
5886
+ longafter
5887
+ longchamp aus
5888
+ longchamp bag
5889
+ longchamp handbag
5890
+ longchamp pas
5891
+ longchamp pliage
5892
+ longchamp purse
5893
+ longchamp solde
5894
+ longchamp tasche
5895
+ longchamp tote
5896
+ longchamp uk
5897
+ longchamp-aus
5898
+ longchamp-handbag
5899
+ longchamp-pliage
5900
+ longchamp-purse
5901
+ longchamp-shop
5902
+ longchamp-solde
5903
+ longchamp-tasche
5904
+ longchamp-tote
5905
+ longchamp-uk
5906
+ longchamp.php
5907
+ longchampaus
5908
+ longchampbag
5909
+ longchamphandbag
5910
+ longchamplondon
5911
+ longchampoffici
5912
+ longchampout
5913
+ longchampp
5914
+ longchamppurse
5915
+ longchampsa
5916
+ longchampshop
5917
+ longchampsolde
5918
+ longchamptasche
5919
+ longchamptote
5920
+ longchampuk
5921
+ lookingfor
5922
+ loorg.de
5923
+ lorazepam
5924
+ lortab
5925
+ lose-weight
5926
+ loseweight
5927
+ loteprednol
5928
+ lotto-tip
5929
+ lottotip
5930
+ louboutin canad
5931
+ louboutin cheap
5932
+ louboutin discount
5933
+ louboutin out
5934
+ louboutin pas
5935
+ louboutin platform
5936
+ louboutin pump
5937
+ louboutin red
5938
+ louboutin sale
5939
+ louboutin shoe
5940
+ louboutin solde
5941
+ louboutin uk
5942
+ louboutin-chau
5943
+ louboutin-cheap
5944
+ louboutin-discount
5945
+ louboutin-out
5946
+ louboutin-pas
5947
+ louboutin-platform
5948
+ louboutin-pump
5949
+ louboutin-red
5950
+ louboutin-sale
5951
+ louboutin-shoe
5952
+ louboutin-solde
5953
+ louboutin8
5954
+ louboutindiscount
5955
+ louboutinfr
5956
+ loubouting
5957
+ louboutinout
5958
+ louboutinpas
5959
+ louboutinpascher
5960
+ louboutins pas
5961
+ louboutins-pas
5962
+ louboutinsale
5963
+ louboutinshoe
5964
+ louboutinsolde
5965
+ louboutinspas
5966
+ louboutinuk
5967
+ louis vitton
5968
+ louis vuittone
5969
+ louis_vuitton
5970
+ louis-vuitton
5971
+ louis-vuittone
5972
+ louis+vuitton
5973
+ louisvuit.
5974
+ louisvuitton
5975
+ louiswuitton
5976
+ love connector
5977
+ love-connector
5978
+ loved onein
5979
+ loved-onein
5980
+ lovelv
5981
+ lovely thong
5982
+ lovely-thong
5983
+ lovelyto
5984
+ lovemyhair
5985
+ lovingnatural
5986
+ low priced
5987
+ low-cost-
5988
+ low-priced
5989
+ lowpriced
5990
+ loyalty today
5991
+ loyalty-today
5992
+ loϲal
5993
+ lublin.
5994
+ lublina.
5995
+ luck jersey
5996
+ luck-jersey
5997
+ luckjersey
5998
+ luggagetote
5999
+ lululemon outlet
6000
+ lululemon-outlet
6001
+ lumigan
6002
+ luminor watch
6003
+ luminor-watch
6004
+ luminorwatch
6005
+ lunarglide
6006
+ lunarlon
6007
+ lunderground
6008
+ lunette oakley
6009
+ lunette solde
6010
+ lunette-oakley
6011
+ lunette-solde
6012
+ lunetteoakley
6013
+ lunettes oakley
6014
+ lunettes-de-soleil
6015
+ lunettes-oakley
6016
+ lunettesdesoleil
6017
+ lunettesoakley
6018
+ lunettesolde
6019
+ lunettespaschere
6020
+ lupusinfo
6021
+ lux-replica
6022
+ luxreplica
6023
+ luxury chanel
6024
+ luxury-brand
6025
+ luxury-chanel
6026
+ luxury-replica
6027
+ luxurybrand
6028
+ luxurychanel
6029
+ luxuryreplica
6030
+ lv austr
6031
+ lv bag
6032
+ lv brasil
6033
+ lv factory
6034
+ lv france
6035
+ lv-bag
6036
+ lv-discount
6037
+ lv-handbag
6038
+ lv-jp
6039
+ lv-out
6040
+ lv-replica
6041
+ lv-uk
6042
+ lvbag
6043
+ lvdiscount
6044
+ lvforsale
6045
+ lvhandbag
6046
+ lviv
6047
+ lvout
6048
+ lvreplica
6049
+ lvsale
6050
+ lvuk
6051
+ m88day
6052
+ mac-cosmetic
6053
+ mac-makeup
6054
+ macha-slim
6055
+ machaslim
6056
+ maclipgloss
6057
+ macmakeup
6058
+ madeknown
6059
+ madeye30
6060
+ magazine/page1
6061
+ magazine/page2
6062
+ magicmoncler
6063
+ magnificent article
6064
+ magnificent-article
6065
+ mail_
6066
+ mail.ru
6067
+ maillot man
6068
+ maillot ukraine
6069
+ maillot-enfant
6070
+ maillot-maillot
6071
+ maillot-man
6072
+ maillot-ukraine
6073
+ maillotman
6074
+ maillotukraine
6075
+ main longchamp
6076
+ main-longchamp
6077
+ main.htm
6078
+ main/main
6079
+ mainlongchamp
6080
+ majesticriver
6081
+ make money
6082
+ make-backup
6083
+ make-million
6084
+ make-money
6085
+ makebaby
6086
+ makeme
6087
+ makemoney
6088
+ makersnow
6089
+ makeup.blog
6090
+ making money
6091
+ making-money
6092
+ makingmoney
6093
+ maklare
6094
+ male enhance
6095
+ male-enhance
6096
+ maleenhance
6097
+ malepower
6098
+ malwareremov
6099
+ manage_
6100
+ manage/new
6101
+ management-software
6102
+ manchesterhotel
6103
+ manicshop
6104
+ manner puma
6105
+ månner puma
6106
+ manner-puma
6107
+ månner-puma
6108
+ mannerpuma
6109
+ månnerpuma
6110
+ manning jersey
6111
+ manning-jersey
6112
+ manningjersey
6113
+ manor escort
6114
+ manor-escort
6115
+ maran-train
6116
+ marant boot
6117
+ marant shoe
6118
+ marant sneak
6119
+ marant-boot
6120
+ marant-shoe
6121
+ marant-sneak
6122
+ marantboot
6123
+ marantrain
6124
+ marantshoe
6125
+ marantsneak
6126
+ marcjacobsjap
6127
+ marcjacobsjp
6128
+ margreet.
6129
+ mariage hugo
6130
+ mariage original
6131
+ mariage-hugo
6132
+ mariage-original
6133
+ marijuana fact
6134
+ marijuana-fact
6135
+ marker http
6136
+ markerboss
6137
+ markerdude
6138
+ markergaul
6139
+ market prices
6140
+ market samurai
6141
+ market-prices
6142
+ market-research.
6143
+ market-researching.
6144
+ market-samurai
6145
+ marketing online
6146
+ marketing samurai
6147
+ marketing-blog
6148
+ marketing-book
6149
+ marketing-market
6150
+ marketing-online
6151
+ marketing-samurai
6152
+ marketing-tip
6153
+ marketing.in
6154
+ marketingblog
6155
+ marketingbook
6156
+ marketinghero
6157
+ marketingsamurai
6158
+ marketingtip
6159
+ marketingxchange
6160
+ marketnn
6161
+ marketsamurai
6162
+ marlboro 100
6163
+ marlboro cig
6164
+ marlboro gold
6165
+ marlboro-100
6166
+ marlboro-cig
6167
+ marlboro-gold
6168
+ marlboro100
6169
+ marseille http
6170
+ marvelous post
6171
+ marvelous-post
6172
+ mass-facebook
6173
+ massarticle
6174
+ massive-web
6175
+ masszaz
6176
+ mastablasta
6177
+ master.ru
6178
+ mastermind-team
6179
+ mastermindteam
6180
+ matchcash
6181
+ matthewsjersey
6182
+ matural
6183
+ max griffey
6184
+ max sale
6185
+ max-griffey
6186
+ max-sale
6187
+ maxalt
6188
+ maxgriffey
6189
+ maxsale
6190
+ may-help-you
6191
+ mbt baridi
6192
+ mbt boot
6193
+ mbt chapa
6194
+ mbt clearance
6195
+ mbt exercise
6196
+ mbt footwear
6197
+ mbt fora
6198
+ mbt men
6199
+ mbt online
6200
+ mbt outlet
6201
+ mbt panda
6202
+ mbt sale
6203
+ mbt sandal
6204
+ mbt scarpe
6205
+ mbt schuhe
6206
+ mbt shoe
6207
+ mbt shop
6208
+ mbt special
6209
+ mbt tariki
6210
+ mbt tembea
6211
+ mbt train
6212
+ mbt tunisha
6213
+ mbt vanzari
6214
+ mbt women
6215
+ mbt_
6216
+ mbt-baridi
6217
+ mbt-boot
6218
+ mbt-carpe
6219
+ mbt-chapa
6220
+ mbt-clearance
6221
+ mbt-exercise
6222
+ mbt-footwear
6223
+ mbt-fora
6224
+ mbt-japan
6225
+ mbt-men
6226
+ mbt-online
6227
+ mbt-outlet
6228
+ mbt-panda
6229
+ mbt-sale
6230
+ mbt-sandal
6231
+ mbt-schuhe
6232
+ mbt-shoe
6233
+ mbt-shop
6234
+ mbt-special
6235
+ mbt-tariki
6236
+ mbt-tembea
6237
+ mbt-train
6238
+ mbt-tunisha
6239
+ mbt-vanzari
6240
+ mbt-women
6241
+ mbtbaridi
6242
+ mbtboot
6243
+ mbtchapa
6244
+ mbtclearance
6245
+ mbtexercise
6246
+ mbtfootwear
6247
+ mbtfora
6248
+ mbtgun
6249
+ mbtjapan
6250
+ mbtmen
6251
+ mbtonline
6252
+ mbtoutlet
6253
+ mbtpanda
6254
+ mbtsale
6255
+ mbtsandal
6256
+ mbtschuhe
6257
+ mbtshoe
6258
+ mbtshop
6259
+ mbtsko
6260
+ mbtspecial
6261
+ mbttariki
6262
+ mbttembea
6263
+ mbttrain
6264
+ mbttunisha
6265
+ mbtvanzari
6266
+ mbtwomen
6267
+ mckinqi
6268
+ mcm backpack
6269
+ mcm bag
6270
+ mcm handbag
6271
+ mcm-backpack
6272
+ mcm-bag
6273
+ mcm-handbag
6274
+ mcm.co
6275
+ mcmbackpack
6276
+ mcqueen club
6277
+ mcqueen dress
6278
+ mcqueen leopard
6279
+ mcqueen online
6280
+ mcqueen pashmin
6281
+ mcqueen shoe
6282
+ mcqueen silk
6283
+ mcqueen-club
6284
+ mcqueen-dress
6285
+ mcqueen-leopard
6286
+ mcqueen-online
6287
+ mcqueen-pashmin
6288
+ mcqueen-shoe
6289
+ mcqueen-silk
6290
+ mcqueenclub
6291
+ mcqueendress
6292
+ mcqueensilk
6293
+ me passionne
6294
+ me-passionne
6295
+ meandyou
6296
+ meble gabinetowe
6297
+ meble ogrodowe
6298
+ meble-gabinetowe
6299
+ meble-ogrodowe
6300
+ meblowy
6301
+ mechpromo.
6302
+ meclizine
6303
+ med-shop
6304
+ medbaz
6305
+ medecine
6306
+ medeniz
6307
+ media-palitra
6308
+ mediapalitra
6309
+ medicarefraud
6310
+ medieval-costume
6311
+ medigital
6312
+ medikal.co
6313
+ medizinische
6314
+ medphrase
6315
+ medshop
6316
+ meilleur casino
6317
+ meilleur-casino
6318
+ meilleurs casino
6319
+ meilleurs-casino
6320
+ melatonin
6321
+ meloxicam
6322
+ member_
6323
+ member.php
6324
+ memberlist.php
6325
+ members_
6326
+ membership hack
6327
+ membership-hack
6328
+ membership.php
6329
+ membershiphack
6330
+ men boost
6331
+ men handbag
6332
+ men-boost
6333
+ men-handbag
6334
+ men+shoe
6335
+ menboost
6336
+ mens coach
6337
+ mens-coach
6338
+ mens+coach
6339
+ menseekingwom
6340
+ mentalprocess
6341
+ menu/menu
6342
+ mequinol
6343
+ meratol
6344
+ mercantilism
6345
+ mercati di
6346
+ mercati-di
6347
+ mercenary.co
6348
+ meridia
6349
+ messengerstyle
6350
+ metacam
6351
+ metallo
6352
+ methadone
6353
+ methionine
6354
+ methode argent
6355
+ methode pour
6356
+ methode-argent
6357
+ methode-pour
6358
+ methodeargent
6359
+ methodepour
6360
+ metlifecare
6361
+ metronidazole
6362
+ mezzo louis
6363
+ mezzo-louis
6364
+ mezzolouis
6365
+ miami escort
6366
+ miami-escort
6367
+ michael-kors
6368
+ michael+kors
6369
+ michaelkors
6370
+ mieszkania
6371
+ mieszkanie
6372
+ milano scarpe
6373
+ milano-scarpe
6374
+ milanoscarpe
6375
+ milanosjapan
6376
+ mild activ
6377
+ mild-activ
6378
+ milendress
6379
+ millen au
6380
+ millen clearance
6381
+ millen color
6382
+ millen colour
6383
+ millen dress
6384
+ millen factory
6385
+ millen jacket
6386
+ millen out
6387
+ millen outlet
6388
+ millen shop
6389
+ millen uk
6390
+ millen-au
6391
+ millen-clearance
6392
+ millen-color
6393
+ millen-colour
6394
+ millen-dress
6395
+ millen-factory
6396
+ millen-jacket
6397
+ millen-out
6398
+ millen-outlet
6399
+ millen-shop
6400
+ millen-uk
6401
+ millenclearance
6402
+ millencolour
6403
+ millenjacket
6404
+ millenoutlet
6405
+ millenshop
6406
+ minecraftfree
6407
+ minicredit
6408
+ mintcoin
6409
+ minumum
6410
+ miracle-discount
6411
+ miraclediscount
6412
+ mirapex
6413
+ mister-design
6414
+ misterboy
6415
+ mittelx
6416
+ miu miu
6417
+ miu sunglass
6418
+ miu-miu
6419
+ miu-sunglass
6420
+ miumiu
6421
+ miusunglass
6422
+ mixed-race
6423
+ mixedrace
6424
+ mkhandbag
6425
+ mkout
6426
+ mlb cap
6427
+ mlb-cap
6428
+ mlbcap
6429
+ mlm business
6430
+ mlm lead
6431
+ mlm-business
6432
+ mlm-lead
6433
+ mlmlead
6434
+ mlskev
6435
+ mlsp suit
6436
+ mlsp-suit
6437
+ mlspweapon
6438
+ mmcenter.in
6439
+ mobi/news
6440
+ mobilabonnementer
6441
+ mobile sim
6442
+ mobile-phone
6443
+ mobistealth
6444
+ moczanowa
6445
+ modafinil
6446
+ models.in
6447
+ moderowany
6448
+ moduleinstance
6449
+ modules.php
6450
+ moldremov
6451
+ monclear
6452
+ moncler berriat
6453
+ moncler cap
6454
+ moncler cloth
6455
+ moncler coat
6456
+ moncler donn
6457
+ moncler femme
6458
+ moncler firenze
6459
+ moncler giub
6460
+ moncler handbag
6461
+ moncler homme
6462
+ moncler jack
6463
+ moncler jacke
6464
+ moncler jassen
6465
+ moncler jura
6466
+ moncler klassiker
6467
+ moncler man
6468
+ moncler men
6469
+ moncler online
6470
+ moncler out
6471
+ moncler padova
6472
+ moncler paris
6473
+ moncler parka
6474
+ moncler pas
6475
+ moncler pascher
6476
+ moncler piumini
6477
+ moncler polo
6478
+ moncler pour
6479
+ moncler prezzi
6480
+ moncler pullover
6481
+ moncler quincy
6482
+ moncler sito
6483
+ moncler ski
6484
+ moncler sold
6485
+ moncler store
6486
+ moncler strickjacke
6487
+ moncler sweater
6488
+ moncler tibet
6489
+ moncler uk
6490
+ moncler uomo
6491
+ moncler vast
6492
+ moncler väst
6493
+ moncler vente
6494
+ moncler vest
6495
+ moncler vos
6496
+ moncler weste
6497
+ moncler westen
6498
+ moncler--
6499
+ moncler-berriat
6500
+ moncler-cap
6501
+ moncler-cloth
6502
+ moncler-coat
6503
+ moncler-donn
6504
+ moncler-femme
6505
+ moncler-firenze
6506
+ moncler-giub
6507
+ moncler-handbag
6508
+ moncler-homme
6509
+ moncler-jack
6510
+ moncler-jacke
6511
+ moncler-jassen
6512
+ moncler-jura
6513
+ moncler-klassiker
6514
+ moncler-man
6515
+ moncler-men
6516
+ moncler-online
6517
+ moncler-out
6518
+ moncler-padova
6519
+ moncler-paris
6520
+ moncler-parka
6521
+ moncler-pas
6522
+ moncler-pascher
6523
+ moncler-piumini
6524
+ moncler-polo
6525
+ moncler-pour
6526
+ moncler-prezzi
6527
+ moncler-pullover
6528
+ moncler-quincy
6529
+ moncler-sito
6530
+ moncler-ski
6531
+ moncler-sold
6532
+ moncler-store
6533
+ moncler-strickjacke
6534
+ moncler-sweater
6535
+ moncler-tibet
6536
+ moncler-uk
6537
+ moncler-uomo
6538
+ moncler-vast
6539
+ moncler-väst
6540
+ moncler-vente
6541
+ moncler-vest
6542
+ moncler-vos
6543
+ moncler-weste
6544
+ moncler-westen
6545
+ moncler.arkis
6546
+ monclerberriat
6547
+ monclercap
6548
+ monclercloth
6549
+ monclercoat
6550
+ monclerdonn
6551
+ monclerfemme
6552
+ monclerfirenze
6553
+ monclergiub
6554
+ monclerhandbag
6555
+ monclerhomme
6556
+ monclerjack
6557
+ monclerjacke
6558
+ monclerjassen
6559
+ monclerjura
6560
+ monclerklassiker
6561
+ monclerman
6562
+ monclermen
6563
+ moncleronline
6564
+ monclerout
6565
+ monclerpadova
6566
+ monclerparis
6567
+ monclerparka
6568
+ monclerpas
6569
+ monclerpascher
6570
+ monclerpiumini
6571
+ monclerpolo
6572
+ monclerpour
6573
+ monclerprezzi
6574
+ monclerpullover
6575
+ monclerquincy
6576
+ monclersito
6577
+ monclerski
6578
+ monclersold
6579
+ monclerstore
6580
+ monclerstrickjacke
6581
+ monclersweater
6582
+ monclertibet
6583
+ moncleruk
6584
+ moncleruomo
6585
+ monclervast
6586
+ monclerväst
6587
+ monclervente
6588
+ monclervest
6589
+ monclervos
6590
+ monclerweste
6591
+ monclerwesten
6592
+ monday deal
6593
+ monday sale
6594
+ monday ugg
6595
+ monday-deal
6596
+ monday-sale
6597
+ monday-ugg
6598
+ mondaydeal
6599
+ mondaysale
6600
+ mondayugg
6601
+ money primar
6602
+ money-mak
6603
+ money-primar
6604
+ money-site
6605
+ money-with
6606
+ money.htm
6607
+ moneyfast
6608
+ moneymak
6609
+ moneyprimar
6610
+ monohydrate
6611
+ monroussillon
6612
+ monster beat
6613
+ monster_
6614
+ monster-beat
6615
+ monster-head
6616
+ monster/beat
6617
+ monsterbeat
6618
+ monsterhead
6619
+ monsterjapan
6620
+ monsterjp
6621
+ montblanc boutique
6622
+ montblanc franc
6623
+ montblanc japan
6624
+ montblanc jp
6625
+ montblanc kuge
6626
+ montblanc meister
6627
+ montblanc paris
6628
+ montblanc pen
6629
+ montblanc sold
6630
+ montblanc stylo
6631
+ montblanc-boutique
6632
+ montblanc-franc
6633
+ montblanc-japan
6634
+ montblanc-jp
6635
+ montblanc-kuge
6636
+ montblanc-meister
6637
+ montblanc-paris
6638
+ montblanc-pen
6639
+ montblanc-sold
6640
+ montblanc-stylo
6641
+ montblancboutique
6642
+ montblancfranc
6643
+ montblancjapan
6644
+ montblancjp
6645
+ montblanckuge
6646
+ montblancmeister
6647
+ montblancparis
6648
+ montblancpen
6649
+ montblancsold
6650
+ montblancstylo
6651
+ montrefemme
6652
+ more-deal
6653
+ morelvjp
6654
+ morpg
6655
+ mortgage.htm
6656
+ mortgagecalc
6657
+ moscow-model
6658
+ most-effective
6659
+ mostra video
6660
+ mostra-video
6661
+ mostravideo
6662
+ movie-online
6663
+ movie-zone
6664
+ movieonline
6665
+ movies-online
6666
+ movies-zone
6667
+ moviesandfilm
6668
+ moviesdl
6669
+ moviesonline
6670
+ movieszone
6671
+ moviezone
6672
+ moгe
6673
+ mp3-download
6674
+ mp3la.ru
6675
+ mp3player
6676
+ mpnth
6677
+ mrant sneak
6678
+ mrant-sneak
6679
+ mrantsneak
6680
+ msgnum
6681
+ much-boot
6682
+ much-gucci
6683
+ muchgucci
6684
+ mulberry bag
6685
+ mulberry handbag
6686
+ mulberry oak
6687
+ mulberry out
6688
+ mulberry purse
6689
+ mulberry tasker
6690
+ mulberry top
6691
+ mulberry uk
6692
+ mulberry-bag
6693
+ mulberry-fashion
6694
+ mulberry-handbag
6695
+ mulberry-oak
6696
+ mulberry-purse
6697
+ mulberry-tasker
6698
+ mulberry-top
6699
+ mulberry-uk
6700
+ mulberrybag
6701
+ mulberryfashion
6702
+ mulberryhandbag
6703
+ mulberrypurse
6704
+ mulberrytop
6705
+ muscle-suppl
6706
+ muscles exercis
6707
+ muscles-exercis
6708
+ musclesuppl
6709
+ muscular abdomen
6710
+ muscular-abdomen
6711
+ muscularwom
6712
+ mustangs http
6713
+ mutuelle sante
6714
+ mutuelle-sante
6715
+ mutuelles sante
6716
+ mutuelles-sante
6717
+ muzyczna
6718
+ muzyczny
6719
+ my bebo
6720
+ my blog
6721
+ my hermes
6722
+ my homepag
6723
+ my online
6724
+ my weblog
6725
+ my website
6726
+ my-bebo
6727
+ my-blog
6728
+ my-hermes
6729
+ my-homepag
6730
+ my-new-ip
6731
+ my-online
6732
+ my-virus
6733
+ my-weblog
6734
+ my-website
6735
+ mydead-
6736
+ mydomain
6737
+ myfitness
6738
+ mygiftcard
6739
+ myhermes
6740
+ myknee
6741
+ myleadsystem
6742
+ mylupus
6743
+ mynewsite
6744
+ mynfl
6745
+ myonline
6746
+ myqrop
6747
+ myreview.co
6748
+ mytest
6749
+ myvirus
6750
+ myweblog
6751
+ nail_art
6752
+ nail-art
6753
+ nail-fest
6754
+ nailart
6755
+ nailfest
6756
+ nailsjapan
6757
+ najlepsze
6758
+ nakedteen
6759
+ naltrexone
6760
+ name-brand
6761
+ nanogold
6762
+ naproxen
6763
+ nat&#252;rlich
6764
+ natura.it
6765
+ natural cure
6766
+ natural-cure
6767
+ natural-way
6768
+ naturalcure
6769
+ naturalovarian
6770
+ naturalway
6771
+ natureto
6772
+ natürlich
6773
+ nba cappelli
6774
+ nba jersey
6775
+ nba_
6776
+ nba-cappelli
6777
+ nba-jersey
6778
+ nbajersey
6779
+ nbshoe
6780
+ need sex
6781
+ need-sex
6782
+ needmoney
6783
+ needsex
6784
+ negozi burberry
6785
+ negozi milano
6786
+ negozi online
6787
+ negozi-burberry
6788
+ negozi-milano
6789
+ negozi-online
6790
+ negoziburberry
6791
+ negozimilano
6792
+ negozio-hollister
6793
+ negoziohollister
6794
+ negozionline
6795
+ net/bilder
6796
+ net/fr/
6797
+ net/members/
6798
+ netload.in
6799
+ network scam
6800
+ network truth
6801
+ network-scam
6802
+ network-truth
6803
+ networkscam
6804
+ networktruth
6805
+ neurontin
6806
+ new gucci
6807
+ new jordan
6808
+ new weblog
6809
+ new-article
6810
+ new-balance
6811
+ new-gucci
6812
+ new-jordan
6813
+ new-oakley
6814
+ newarrival
6815
+ newarticle
6816
+ newbalance1
6817
+ newbalance2
6818
+ newblance-20
6819
+ newblance20
6820
+ newest news
6821
+ newest-news
6822
+ newgucci
6823
+ newhong
6824
+ newjordan
6825
+ newoakley
6826
+ newport 100s
6827
+ newport-100s
6828
+ newport100s
6829
+ news.in
6830
+ news/article
6831
+ newsarticle
6832
+ newss.
6833
+ newwebsite
6834
+ nexopia
6835
+ nfl austr
6836
+ nfl italia
6837
+ nfl jers
6838
+ nfl shop
6839
+ nfl-beanie
6840
+ nfl-italia
6841
+ nfl-jers
6842
+ nfl-official
6843
+ nfl-shop
6844
+ nfljers
6845
+ nflofficial
6846
+ nflshop
6847
+ nfr.cfm
6848
+ nhl jersey
6849
+ nhl replica
6850
+ nhl-jersey
6851
+ nhl-replica
6852
+ nhlreplica
6853
+ niaspan
6854
+ nice paragraph
6855
+ nice practice
6856
+ nice-paragraph
6857
+ nice-practice
6858
+ nicki-mariah
6859
+ nicoban
6860
+ nicolasbit
6861
+ nicе
6862
+ nieruchomosci
6863
+ nike 5.0
6864
+ nike free
6865
+ nike jersey
6866
+ nike jordan
6867
+ nike kd
6868
+ nike mercurial
6869
+ nike run
6870
+ nike shoe
6871
+ nike total
6872
+ nike_
6873
+ nike-and-shoe
6874
+ nike-blazer
6875
+ nike-dunk
6876
+ nike-free
6877
+ nike-freerun
6878
+ nike-jersey
6879
+ nike-jordan
6880
+ nike-kd
6881
+ nike-main
6882
+ nike-mercurial
6883
+ nike-run
6884
+ nike-shoe
6885
+ nike-total
6886
+ nike1
6887
+ nike2
6888
+ nikeairmax
6889
+ nikeairshop
6890
+ nikeandshoe
6891
+ nikeause
6892
+ nikeblazer
6893
+ nikedunk
6894
+ nikefree
6895
+ nikefreerun
6896
+ nikejersey
6897
+ nikejordan
6898
+ nikemain
6899
+ nikepasch
6900
+ nikerun
6901
+ nikeshoe
6902
+ nikeshop
6903
+ nikesportjap
6904
+ nikesportjp
6905
+ niketokyo
6906
+ niketotal
6907
+ ninja sword
6908
+ ninja-sword
6909
+ ninjasword
6910
+ niselv.co
6911
+ nitraazepam
6912
+ nitrazepam
6913
+ nizoral
6914
+ nm.ru
6915
+ no collateral
6916
+ no guarant
6917
+ no-cache
6918
+ no-collateral
6919
+ no-credit
6920
+ no-fuss
6921
+ no-guarant
6922
+ no-hassle
6923
+ no-prescript
6924
+ no1.co
6925
+ nocache
6926
+ nocredit
6927
+ nohassle
6928
+ nolvadex
6929
+ norge canad
6930
+ norge-canad
6931
+ norgecanad
6932
+ north_face
6933
+ north+face
6934
+ northface pascher
6935
+ northface-canad
6936
+ northface-jack
6937
+ northface-out
6938
+ northface-pascher
6939
+ northface-sale
6940
+ northface-uk
6941
+ northface-us
6942
+ northfacecanad
6943
+ northfacejack
6944
+ northfaceout
6945
+ northfacepascher
6946
+ northfacesale
6947
+ northfacetr
6948
+ northfaceuk
6949
+ northfaceus
6950
+ northfaceya
6951
+ northfce
6952
+ norvasc
6953
+ not-dienst
6954
+ not|
6955
+ notdienst
6956
+ notraty
6957
+ nouveau maillot
6958
+ nouveau-maillot
6959
+ nouveaumaillot
6960
+ nouvelles sneaker
6961
+ nouvelles-sneaker
6962
+ novinki_
6963
+ now.in
6964
+ nude-ass
6965
+ nude.htm
6966
+ nufactur
6967
+ nеar
6968
+ nօt
6969
+ oakeyspascher
6970
+ oakley canad
6971
+ oakley caveat
6972
+ oakley cross
6973
+ oakley five
6974
+ oakley frogskin
6975
+ oakley glass
6976
+ oakley juliet
6977
+ oakley out
6978
+ oakley polarized
6979
+ oakley sale
6980
+ oakley sunglass
6981
+ oakley_
6982
+ oakley-active
6983
+ oakley-canad
6984
+ oakley-caveat
6985
+ oakley-cheap
6986
+ oakley-cross
6987
+ oakley-five
6988
+ oakley-juliet
6989
+ oakley-out
6990
+ oakley-polarized
6991
+ oakley-store
6992
+ oakley-straight
6993
+ oakley-sunglass
6994
+ oakleyactive
6995
+ oakleycanad
6996
+ oakleycaveat
6997
+ oakleycheap
6998
+ oakleycross
6999
+ oakleyjuliet
7000
+ oakleymedusa
7001
+ oakleyout
7002
+ oakleypascher
7003
+ oakleyru
7004
+ oakleys sunglass
7005
+ oakleys-sunglass
7006
+ oakleys.net
7007
+ oakleysale
7008
+ oakleysj
7009
+ oakleyssunglass
7010
+ oakleystore
7011
+ oakleysuk
7012
+ oakleysunglass
7013
+ oakleytokyo
7014
+ oakleyuk
7015
+ öáøåâïïê
7016
+ obey posse
7017
+ obey-posse
7018
+ obtain consol
7019
+ obtain-consol
7020
+ obuwia
7021
+ obuwie
7022
+ oculosfeminino
7023
+ odszkodowania
7024
+ odziez
7025
+ oem-software
7026
+ oemsoftware
7027
+ of herpes
7028
+ of internet
7029
+ of-herpes
7030
+ of-internet
7031
+ offer outlet
7032
+ offer watch
7033
+ offer-outlet
7034
+ offer-watch
7035
+ offer.net
7036
+ offer.weebly
7037
+ offeroutlet
7038
+ offerwatch
7039
+ office autopilot
7040
+ office-autopilot
7041
+ officeautopilot
7042
+ official website
7043
+ official-sale
7044
+ official-steeler
7045
+ official-style
7046
+ official-ugg
7047
+ official-website
7048
+ officialmailsite
7049
+ officialsale
7050
+ officialsteeler
7051
+ officialstyle
7052
+ officialteamshop
7053
+ officialugg
7054
+ officialwebsite
7055
+ offight
7056
+ ofhuman
7057
+ oit|
7058
+ ojectx
7059
+ ok-cheap
7060
+ ok-sex
7061
+ okanyway
7062
+ okcanadagoose
7063
+ okcheap
7064
+ okpay
7065
+ oksex
7066
+ oksunglass
7067
+ old|
7068
+ once-in-a-lifetime
7069
+ one nike
7070
+ one-nike
7071
+ oneminutesite
7072
+ onenike
7073
+ onestrap
7074
+ online cash
7075
+ online casino
7076
+ online class
7077
+ online dating
7078
+ online espana
7079
+ online españa
7080
+ online gambling
7081
+ online gry
7082
+ online loan
7083
+ online out
7084
+ online pokie
7085
+ online shoe
7086
+ online shop
7087
+ online usa
7088
+ online-blog
7089
+ online-business
7090
+ online-cash
7091
+ online-casino
7092
+ online-cert
7093
+ online-class
7094
+ online-dating
7095
+ online-espana
7096
+ online-españa
7097
+ online-gambling
7098
+ online-gry
7099
+ online-invest
7100
+ online-kredit
7101
+ online-loan
7102
+ online-market
7103
+ online-med
7104
+ online-money
7105
+ online-out
7106
+ online-pokie
7107
+ online-sale
7108
+ online-shoe
7109
+ online-shop
7110
+ online-store
7111
+ online-usa
7112
+ online.de
7113
+ online.htm
7114
+ online.in
7115
+ online.web
7116
+ onlinebackup.
7117
+ onlineblog
7118
+ onlinebusiness
7119
+ onlinebuy
7120
+ onlinecash
7121
+ onlinecasino
7122
+ onlinecert
7123
+ onlinedating
7124
+ onlinede.
7125
+ onlinegambling
7126
+ onlineinvest
7127
+ onlinejp
7128
+ onlinekredit
7129
+ onlineloan
7130
+ onlinemed
7131
+ onlinemoney
7132
+ onlineout
7133
+ onlinepoker
7134
+ onlinepris
7135
+ onlines.co
7136
+ onlines.web
7137
+ onlinesale
7138
+ onlineshoe
7139
+ onlineshop
7140
+ onlinestore
7141
+ only pokie
7142
+ only-deal
7143
+ only-pokie
7144
+ onlyway
7145
+ onsale-
7146
+ onsale.asp
7147
+ onsale.co
7148
+ onsale.htm
7149
+ onsale.php
7150
+ onsales.co
7151
+ openair
7152
+ opinion.in
7153
+ opinions.in
7154
+ option binaire
7155
+ option-binaire
7156
+ options binaire
7157
+ options-binaire
7158
+ options-trad
7159
+ optionstrad
7160
+ oral-sex
7161
+ order_type
7162
+ ordersoma
7163
+ organogold
7164
+ orgazma
7165
+ oriflame
7166
+ original http
7167
+ orlistat
7168
+ osobistosci
7169
+ osobistości
7170
+ otonanocoach
7171
+ otoplasty
7172
+ otvety
7173
+ outelt
7174
+ outilclient
7175
+ outlet bag
7176
+ outlet canad
7177
+ outlet france
7178
+ outlet handbag
7179
+ outlet hermes
7180
+ outlet hogan
7181
+ outlet italia
7182
+ outlet louis
7183
+ outlet moncler
7184
+ outlet oakley
7185
+ outlet online
7186
+ outlet shoe
7187
+ outlet store
7188
+ outlet uk
7189
+ outlet usa
7190
+ outlet vancouver
7191
+ outlet woolrich
7192
+ outlet_
7193
+ outlet-austr
7194
+ outlet-canad
7195
+ outlet-france
7196
+ outlet-hermes
7197
+ outlet-hogan
7198
+ outlet-italia
7199
+ outlet-japan
7200
+ outlet-louis
7201
+ outlet-mart
7202
+ outlet-moncler
7203
+ outlet-online
7204
+ outlet-sale
7205
+ outlet-shoe
7206
+ outlet-shop
7207
+ outlet-store
7208
+ outlet-uk
7209
+ outlet-usa
7210
+ outlet-vancouver
7211
+ outlet-web
7212
+ outlet-woolrich
7213
+ outlet.co
7214
+ outlet.net
7215
+ outlet.org
7216
+ outlet.uk
7217
+ outlet.us
7218
+ outlet.weebly
7219
+ outlet4u
7220
+ outlet2012
7221
+ outlet2013
7222
+ outlet2014
7223
+ outletaustr
7224
+ outletbag
7225
+ outletcanad
7226
+ outletforsale
7227
+ outletfrance
7228
+ outlethermes
7229
+ outletitalia
7230
+ outletjapan
7231
+ outletlouis
7232
+ outletlove
7233
+ outletmart
7234
+ outletmoncler
7235
+ outletonline
7236
+ outlets-online
7237
+ outlets-sale
7238
+ outlets.co
7239
+ outlets.net
7240
+ outlets.org
7241
+ outlets.us
7242
+ outletsale
7243
+ outletshoe
7244
+ outletshop
7245
+ outletsonline
7246
+ outletssale
7247
+ outletstore
7248
+ outletuk
7249
+ outletusa
7250
+ outletweb
7251
+ outletwoolrich
7252
+ outplacement-compan
7253
+ outplacements
7254
+ outsourcing-compan
7255
+ ovariancyst
7256
+ own blogroll
7257
+ own-blogroll
7258
+ ownersinsur
7259
+ oxycodone
7260
+ oxycontin
7261
+ oympia
7262
+ oьtɑin
7263
+ p90x
7264
+ packersjersey
7265
+ page_
7266
+ page.tl
7267
+ page/pag
7268
+ pagss.htm
7269
+ pain-behind
7270
+ pain-relief.
7271
+ painbehind
7272
+ painrelief.
7273
+ paintedfor
7274
+ panda-shoe
7275
+ pandashoe
7276
+ pandora charm
7277
+ pandora online
7278
+ pandora sale
7279
+ pandora-bracelet
7280
+ pandora-charm
7281
+ pandora-jewelry
7282
+ pandora-online
7283
+ pandora-sale
7284
+ pandoraau
7285
+ pandorabracelet
7286
+ pandoracharm
7287
+ pandorajewelry
7288
+ pandorauk
7289
+ panerai clock
7290
+ panerai watch
7291
+ panerai-clock
7292
+ panerai-watch
7293
+ paneraiclock
7294
+ paneraiwatch
7295
+ panier site
7296
+ panier-site
7297
+ paniersite
7298
+ panthers jersey
7299
+ panthers merch
7300
+ panthers store
7301
+ panthers-jersey
7302
+ panthers-merch
7303
+ panthers-store
7304
+ panthersmerch
7305
+ panthersstore
7306
+ panty pic
7307
+ panty play
7308
+ panty sex
7309
+ panty-pic
7310
+ panty-play
7311
+ panty-sex
7312
+ pantymania
7313
+ pantypic
7314
+ pantyplay
7315
+ par/index
7316
+ paradisiaque
7317
+ paragraph writing
7318
+ paragraph-writing
7319
+ parajumpers
7320
+ parchet triplu
7321
+ parchet-triplu
7322
+ paretologic
7323
+ paris http
7324
+ paris model
7325
+ paris-for
7326
+ paris-model
7327
+ paris-royal
7328
+ parismodel
7329
+ parkiety
7330
+ part mariage
7331
+ part-mariage
7332
+ particular article
7333
+ particular-article
7334
+ party_feet
7335
+ party-poker
7336
+ partypoker
7337
+ pas cher
7338
+ pas-cher
7339
+ pascher
7340
+ pascherfr
7341
+ pascheroakley
7342
+ passprefix
7343
+ password generat
7344
+ password-generat
7345
+ passwort
7346
+ passwrot
7347
+ patagonia-zone
7348
+ patagoniazone
7349
+ patrao-online
7350
+ patraoonline
7351
+ patriots hat
7352
+ patriots-hat
7353
+ paulsmith-cheap
7354
+ paulsmith-shop
7355
+ paulsmith1
7356
+ paulsmith2
7357
+ paulsmith201
7358
+ paulsmithcheap
7359
+ paulsmithka
7360
+ paulsmithsa
7361
+ paulsmithshop
7362
+ paulsmithsu
7363
+ paxil
7364
+ pay_day
7365
+ pay-as-you-go
7366
+ payday loan
7367
+ payday-loan
7368
+ payday-on
7369
+ payday.co
7370
+ paydayloan
7371
+ paydaynote
7372
+ paydayon
7373
+ payed off
7374
+ payed-off
7375
+ paypal-cash
7376
+ paypalcash
7377
+ payroll-calc
7378
+ pbrolme
7379
+ pc health
7380
+ pc windows
7381
+ pc-access
7382
+ pc-health
7383
+ pc-windows
7384
+ pcaccess
7385
+ pchealthadvis
7386
+ pcstuff
7387
+ penis.co
7388
+ penisadv
7389
+ penisenlarg
7390
+ penny-auction
7391
+ penny-bid
7392
+ penny-stock
7393
+ pennyauction
7394
+ pennybid
7395
+ pennystock
7396
+ per-week
7397
+ percocet
7398
+ perday.co
7399
+ perfectvpn
7400
+ perfectwriting
7401
+ permission allow
7402
+ permission-allow
7403
+ permonth.co
7404
+ personal-experience
7405
+ personal-injury
7406
+ personalinjury
7407
+ personnalis
7408
+ perweek
7409
+ petencies
7410
+ pflegeversicherung
7411
+ pflegezusatzversicherung
7412
+ pg/blog
7413
+ pg/forum
7414
+ pg/profile
7415
+ pharmacies
7416
+ pharmacy
7417
+ pharmaun
7418
+ phentermine
7419
+ phlebotomy
7420
+ phon-store
7421
+ phone advert
7422
+ phone free
7423
+ phone-advert
7424
+ phone-free
7425
+ phone-jammer
7426
+ phone-lookup
7427
+ phone-number-lookup
7428
+ phone-store
7429
+ phoneadvert
7430
+ phoneforsale
7431
+ phonefree
7432
+ phonejammer
7433
+ phonelookup
7434
+ phonescanad
7435
+ phonesforsale
7436
+ phonestore
7437
+ phonstore
7438
+ photo/online
7439
+ photoeditingdeal
7440
+ php?article
7441
+ php?rowstart
7442
+ php?showuser
7443
+ php?title
7444
+ php5?title
7445
+ phpbb2
7446
+ phpinfo
7447
+ phync
7448
+ pidarashechk
7449
+ pignee
7450
+ pillonline
7451
+ pills.co
7452
+ pillsonline
7453
+ pink large
7454
+ pink-large
7455
+ pinklarge
7456
+ piscine
7457
+ piumini moncler
7458
+ piumini-moncler
7459
+ piuminimoncler
7460
+ piumino moncler
7461
+ piumino-moncler
7462
+ piuminomoncler
7463
+ plansare
7464
+ plavix
7465
+ play-free
7466
+ play-online
7467
+ playerblock
7468
+ playfree
7469
+ playonline
7470
+ plazajp
7471
+ pleasant designed
7472
+ pleasant good
7473
+ pleasant-designed
7474
+ pleasant-good
7475
+ pleassant
7476
+ pleease
7477
+ plombier http
7478
+ plombier paris
7479
+ plombier-paris
7480
+ plumbingservice
7481
+ plus-size
7482
+ plussize
7483
+ plytki
7484
+ plz respond
7485
+ plz-respond
7486
+ poco prezzo
7487
+ poco-prezzo
7488
+ point|
7489
+ points-generator
7490
+ pointsgenerator
7491
+ poished
7492
+ pojapan
7493
+ poker-chip
7494
+ poker-money
7495
+ poker-strateg
7496
+ pokera
7497
+ pokerchip
7498
+ pokermoney
7499
+ pokerstrateg
7500
+ pokie machine
7501
+ pokie online
7502
+ pokie-machine
7503
+ pokie-online
7504
+ pokiemachine
7505
+ pokieonline
7506
+ pokies online
7507
+ pokies-online
7508
+ pokiesonline
7509
+ pokornému
7510
+ polnocno
7511
+ pólnocno
7512
+ północno
7513
+ polo out
7514
+ polo ralph
7515
+ polo_
7516
+ polo-lacoste
7517
+ polo-ralph
7518
+ poloralph
7519
+ polos ralph
7520
+ polos-ralph
7521
+ polosralph
7522
+ popular brand
7523
+ popular-brand
7524
+ popularna
7525
+ popularną markę
7526
+ porn comic
7527
+ porn live
7528
+ porn sex
7529
+ porn vid
7530
+ porn-comic
7531
+ porn-live
7532
+ porn-sex
7533
+ porn-vid
7534
+ porn.
7535
+ pornlive
7536
+ porno gratuit
7537
+ porno http
7538
+ porno stream
7539
+ porno-
7540
+ porno-gratuit
7541
+ porno-stream
7542
+ porno.
7543
+ porno@
7544
+ pornolady
7545
+ pornsex
7546
+ possess
7547
+ post post
7548
+ post_
7549
+ post-post
7550
+ post-service
7551
+ post.much
7552
+ post.pw
7553
+ postcarf
7554
+ posting comment
7555
+ posting-comment
7556
+ posting!
7557
+ posts.asp
7558
+ posttestimonial
7559
+ powerball
7560
+ powerbank
7561
+ pozew.
7562
+ poznajseo
7563
+ poznan
7564
+ pozycjonowanie
7565
+ pozyczka
7566
+ pozyczki
7567
+ pp-class
7568
+ prada bag
7569
+ prada cheap
7570
+ prada dress
7571
+ prada handbag
7572
+ prada online
7573
+ prada out
7574
+ prada sac
7575
+ prada_
7576
+ prada-bag
7577
+ prada-cheap
7578
+ prada-new
7579
+ prada-online
7580
+ prada-out
7581
+ prada-sac
7582
+ pradabag
7583
+ pradacheap
7584
+ pradadesign
7585
+ pradagirl
7586
+ pradanew
7587
+ pradaonline
7588
+ pradaout
7589
+ pradasac
7590
+ prawnik
7591
+ prazosin
7592
+ prednisone
7593
+ pregnancysymptom
7594
+ premarin
7595
+ prematureejaculat
7596
+ premium key
7597
+ premium-account
7598
+ premium-cig
7599
+ premiumcig
7600
+ prentice capital
7601
+ prentice-capital
7602
+ prenticecapital
7603
+ prepaid-credit
7604
+ preparationwise
7605
+ prescription.htm
7606
+ presentation subsequent
7607
+ presentation-subsequent
7608
+ preserveness
7609
+ pressrelease.net
7610
+ pretty worth
7611
+ pretty-worth
7612
+ previcox
7613
+ price-of-gold
7614
+ pricetobook
7615
+ priligy
7616
+ primeessay
7617
+ private ftp
7618
+ private-ftp
7619
+ private-label
7620
+ privatelabel
7621
+ prix ugg
7622
+ prix-ugg
7623
+ prixugg
7624
+ pro key
7625
+ pro review
7626
+ pro-review
7627
+ proactol
7628
+ procedures-for
7629
+ proceesing
7630
+ produce article
7631
+ produce-article
7632
+ producer excellent
7633
+ producer-excellent
7634
+ product
7635
+ product-sale
7636
+ product/product
7637
+ produkcja
7638
+ profesjonal
7639
+ professional 2007
7640
+ professional 2008
7641
+ professional 2010
7642
+ professional-ugg
7643
+ professionals.co
7644
+ professionalugg
7645
+ profile_
7646
+ profile/?u
7647
+ profile/blog
7648
+ profile/profile
7649
+ profiles/blog
7650
+ profiles/profile
7651
+ profissionais
7652
+ profit-margin
7653
+ profit-seek
7654
+ profits-
7655
+ profitseek
7656
+ prohormone
7657
+ proisxozhdenie
7658
+ project-earn
7659
+ prokey
7660
+ prokeyshop
7661
+ prom-dress
7662
+ promo artist
7663
+ promo-artist
7664
+ promo-shop
7665
+ promo-store
7666
+ promo+code
7667
+ promoartist
7668
+ promocja
7669
+ promocode
7670
+ promoshop
7671
+ promostore
7672
+ promosystem
7673
+ promotional bag
7674
+ propecia
7675
+ proper-ugg
7676
+ property pro
7677
+ property-pro
7678
+ propertypro
7679
+ properugg
7680
+ propranolol
7681
+ prostitutki
7682
+ protein-diet
7683
+ proteindiet
7684
+ provewhether
7685
+ provigil
7686
+ proxénétisme
7687
+ prozac-
7688
+ prywatne
7689
+ przepisane
7690
+ przeprowadzki
7691
+ przysiegly
7692
+ psych-clinic
7693
+ psychclinic
7694
+ publica-foto
7695
+ publikacja
7696
+ pucci dress
7697
+ pucci-dress
7698
+ pucci-out
7699
+ puccidress
7700
+ pucciout
7701
+ pufy.
7702
+ puma deutsch
7703
+ puma ferrari
7704
+ puma outlet
7705
+ puma paidat
7706
+ puma schuhe
7707
+ puma sneak
7708
+ puma-deutsch
7709
+ puma-drifter
7710
+ puma-ferrari
7711
+ puma-lauf
7712
+ puma-nice
7713
+ puma-outlet
7714
+ puma-paidat
7715
+ puma-schuhe
7716
+ puma-sneak
7717
+ pumadeutsch
7718
+ pumadrifter
7719
+ pumaferrari
7720
+ pumalauf
7721
+ pumanice
7722
+ pumaoutlet
7723
+ pumapaidat
7724
+ pumaschuhe
7725
+ pumasneak
7726
+ pure-jobs
7727
+ purse forum
7728
+ purse online
7729
+ purse out
7730
+ purse-forum
7731
+ purse-out
7732
+ purse-sale
7733
+ purseout
7734
+ purses online
7735
+ purses out
7736
+ purses-out
7737
+ purses-sale
7738
+ pursesout
7739
+ puzzle maker
7740
+ puzzle-maker
7741
+ puzzlemaker
7742
+ pytanie
7743
+ qampuz
7744
+ qquality
7745
+ qry_
7746
+ qtrade
7747
+ quality article
7748
+ quality post
7749
+ quality-article
7750
+ quality-post
7751
+ quartz-seiko
7752
+ quartzseiko
7753
+ queen chiffon
7754
+ queen clutch
7755
+ queen out
7756
+ queen-chiffon
7757
+ queen-clutch
7758
+ queen-out
7759
+ queenchiffon
7760
+ queenclutch
7761
+ queenjp
7762
+ queenoutlet
7763
+ querireda
7764
+ quick loans
7765
+ quick_
7766
+ quick-loan
7767
+ quickloan
7768
+ quincy femme
7769
+ quincy-femme
7770
+ quincyfemme
7771
+ quit-smoking
7772
+ qvc
7773
+ r?f?rence
7774
+ radikal.ru
7775
+ radiocarpea
7776
+ raiders hat
7777
+ raiders-hat
7778
+ raidershat
7779
+ raloxifene
7780
+ ralph-lauren
7781
+ ramipril
7782
+ rank-build
7783
+ rankbuild
7784
+ ranking:
7785
+ rapid-pay
7786
+ rapidpay
7787
+ rasalinga
7788
+ rastreadores
7789
+ ravensfan
7790
+ ray-ban-aviator
7791
+ ray-ban-folding
7792
+ ray-bans
7793
+ rayban glass
7794
+ rayban_
7795
+ rayban-cheap
7796
+ rayban-glass
7797
+ raybaneye
7798
+ raybanglass
7799
+ raybanpascher
7800
+ raybanslunette
7801
+ raybansuk
7802
+ raybansun
7803
+ raybansunglass
7804
+ raybantokyo
7805
+ raybanuk
7806
+ razadyne
7807
+ readers-base
7808
+ readers' base
7809
+ readers’ base
7810
+ readyto
7811
+ real_estate
7812
+ real-estate-web
7813
+ real-estate.web
7814
+ realestate.co
7815
+ realestate.web
7816
+ realestate.wordpress
7817
+ reallywork.we
7818
+ realtor promo
7819
+ realtor-promo
7820
+ reasons-why
7821
+ reciclable
7822
+ recommended internet
7823
+ records.net
7824
+ recoverynow
7825
+ red christian
7826
+ red ugg
7827
+ red-ugg
7828
+ red+bottom+shoe
7829
+ redbottomshoe
7830
+ redirect_
7831
+ redirect.asp
7832
+ redskinsjersey
7833
+ redsoleshoe
7834
+ redugg
7835
+ redwingjp
7836
+ reebok baseball
7837
+ reebok scarpe
7838
+ reebok-baseball
7839
+ reebok-scarpe
7840
+ reebokscarpe
7841
+ reeview
7842
+ referencement
7843
+ référencement
7844
+ refluks
7845
+ reflux symptom
7846
+ reflux-symptom
7847
+ refluxsymptom
7848
+ reg_
7849
+ regarding blog
7850
+ regarfing
7851
+ registration strateg
7852
+ registration-strateg
7853
+ registrator
7854
+ registry-clean
7855
+ registry-fix
7856
+ registry-repair
7857
+ registry-tool
7858
+ registry+clean
7859
+ registry+fix
7860
+ registry+tool
7861
+ registryclean
7862
+ registryfix
7863
+ registryrepair
7864
+ registrytool
7865
+ reguliatory
7866
+ reirect
7867
+ rejersey.co
7868
+ rejersey.net
7869
+ rekla.
7870
+ reklamowe
7871
+ rekreacja
7872
+ relaxeԁ
7873
+ reliefsecret
7874
+ religion jeans
7875
+ religion-jeans
7876
+ religionjeans
7877
+ rellay
7878
+ remarkable post
7879
+ remarkable-post
7880
+ rent_in
7881
+ rent-car
7882
+ rentinsur
7883
+ replica bag
7884
+ replica birk
7885
+ replica china
7886
+ replica hand
7887
+ replica ip
7888
+ replica jersey
7889
+ replica louis
7890
+ replica nba
7891
+ replica oakley
7892
+ replica rayban
7893
+ replica service
7894
+ replica top
7895
+ replica ugg
7896
+ replica watch
7897
+ replica_
7898
+ replica-bag
7899
+ replica-brand
7900
+ replica-china
7901
+ replica-design
7902
+ replica-gucci
7903
+ replica-hand
7904
+ replica-handbag
7905
+ replica-ip
7906
+ replica-jersey
7907
+ replica-louis
7908
+ replica-nba
7909
+ replica-oakley
7910
+ replica-prada
7911
+ replica-rayban
7912
+ replica-rolex
7913
+ replica-service
7914
+ replica-store
7915
+ replica-top
7916
+ replica-ugg
7917
+ replica-world
7918
+ replica<
7919
+ replica7
7920
+ replica8
7921
+ replicabag
7922
+ replicabrand
7923
+ replicachanel
7924
+ replicachina
7925
+ replicadesign
7926
+ replicagucci
7927
+ replicahand
7928
+ replicahandbag
7929
+ replicaip
7930
+ replicajersey
7931
+ replicalouis
7932
+ replicanba
7933
+ replicaoakley
7934
+ replicaprad
7935
+ replicarayban
7936
+ replicarolex
7937
+ replicaservice
7938
+ replicastore
7939
+ replicatop
7940
+ replicaugg
7941
+ replicawatch
7942
+ replicaworld
7943
+ reports.php
7944
+ resist comment
7945
+ resist-comment
7946
+ resources/styles
7947
+ restoremen
7948
+ restoril
7949
+ results.htm
7950
+ retin-a
7951
+ reverse lookup
7952
+ reverse-lookup
7953
+ reverse-phone
7954
+ reverselookup
7955
+ reversephone
7956
+ review-source
7957
+ review.asp
7958
+ review.blog
7959
+ review.htm
7960
+ review.in
7961
+ reviews.asp
7962
+ reviews.blog
7963
+ reviews.htm
7964
+ reviews.in
7965
+ reviews.net
7966
+ reviews.org
7967
+ reviewsource
7968
+ reviewthe
7969
+ reviewx
7970
+ reviot
7971
+ revolutionjog
7972
+ revolutionstroll
7973
+ reԛuire
7974
+ rheumatoidarthritis
7975
+ rice-cooker
7976
+ ricecooker
7977
+ rich woolrich
7978
+ rich-woolrich
7979
+ richwoolrich
7980
+ right blog
7981
+ right-blog
7982
+ rightblog
7983
+ rilopkais.in
7984
+ rin.in
7985
+ riot points
7986
+ riot-points
7987
+ riotpoints
7988
+ ripoffreport
7989
+ rizatriptan
7990
+ robaxin
7991
+ robe-de-mariee
7992
+ robe-du-mariage
7993
+ robedemariee
7994
+ robedumariage
7995
+ robertby
7996
+ roger-vivier
7997
+ rok.ru
7998
+ rokettube
7999
+ roleplay
8000
+ rolex-watch
8001
+ rolexwatch
8002
+ roofingcontractor
8003
+ ropa belstaff
8004
+ ropa-belstaff
8005
+ ropabelstaff
8006
+ rose-shoe
8007
+ roseshoe
8008
+ rosettastoneeasy
8009
+ rosuvastatin
8010
+ rotating-hot-iron
8011
+ rotatinghotiron
8012
+ rouge moncler
8013
+ rouge-moncler
8014
+ rougemoncler
8015
+ roxy ugg
8016
+ roxy-ugg
8017
+ roxyugg
8018
+ royal-club
8019
+ royalclub
8020
+ róże
8021
+ rozszerzona
8022
+ rpg-online
8023
+ rpgonline
8024
+ rss.htm
8025
+ ru/pub
8026
+ runescape
8027
+ running sneak
8028
+ running-sneak
8029
+ runningsneak
8030
+ rusztowania
8031
+ rіght
8032
+ s.webeden
8033
+ sabo charm
8034
+ sabo out
8035
+ sabo ring
8036
+ sabo sale
8037
+ sabo shop
8038
+ sabo uk
8039
+ sabo-charm
8040
+ sabo-out
8041
+ sabocharm
8042
+ sac celine
8043
+ sac chloe
8044
+ sac hermes
8045
+ sac lancel
8046
+ sac longchamp
8047
+ sac louis
8048
+ sac vanessa
8049
+ sac vuitton
8050
+ sac_lancel
8051
+ sac-celine
8052
+ sac-chloe
8053
+ sac-hermes
8054
+ sac-lancel
8055
+ sac-longchamp
8056
+ sac-louis
8057
+ sac-vanessa
8058
+ sac-vuitton
8059
+ sacguess
8060
+ saclongchamp
8061
+ saclouis
8062
+ sacs longchamps
8063
+ sacs-fr
8064
+ sacs-longchamps
8065
+ sacsfr
8066
+ sacsguess
8067
+ sacslancel
8068
+ sacvanessa
8069
+ sacvuitton
8070
+ sadehap
8071
+ saints jersey
8072
+ saints-jersey
8073
+ saintsjersey
8074
+ saldi online
8075
+ saldi-footwear
8076
+ saldi-online
8077
+ saldifootwear
8078
+ saldionline
8079
+ sale louis
8080
+ sale lulu
8081
+ sale miami
8082
+ sale nederland
8083
+ sale oakley
8084
+ sale template
8085
+ sale-cheap
8086
+ sale-factory
8087
+ sale-jp
8088
+ sale-longchamp
8089
+ sale-louis
8090
+ sale-lulu
8091
+ sale-miami
8092
+ sale-nederland
8093
+ sale-oakley
8094
+ sale-template
8095
+ sale-tokyo
8096
+ sale-training
8097
+ sale.co.
8098
+ sale.weebly
8099
+ sale4u
8100
+ salecanad
8101
+ salecheap
8102
+ salefactory
8103
+ salejp
8104
+ salelouis
8105
+ salelulu
8106
+ salemiami
8107
+ saleoakley
8108
+ saleonline
8109
+ saleout
8110
+ sales-class
8111
+ sales-factory
8112
+ sales-inspir
8113
+ sales-train
8114
+ sales-training
8115
+ sales.co.
8116
+ sales+
8117
+ salesclass
8118
+ salesfactory
8119
+ saleshop
8120
+ salesshop
8121
+ salestrain
8122
+ salestraining
8123
+ saletemplate
8124
+ saletokyo
8125
+ saletraining
8126
+ saleu.co
8127
+ salomon athletic
8128
+ salomon canada
8129
+ salomon-athletic
8130
+ salomon-canada
8131
+ salomonathletic
8132
+ salomoncanada
8133
+ salvia.
8134
+ sameday-loan
8135
+ samedayloan
8136
+ sample@
8137
+ samurai siege
8138
+ samurai-siege
8139
+ sandaljp
8140
+ sandalsjp
8141
+ sanders jersey
8142
+ sanders-jersey
8143
+ sandersjersey
8144
+ sandypasch
8145
+ sante http
8146
+ satchelbag
8147
+ satcheldbag
8148
+ sauvegarde extern
8149
+ sauvegarde-extern
8150
+ sbobet
8151
+ scam.htm
8152
+ scam.in
8153
+ scam.net
8154
+ scam.org
8155
+ scar repair
8156
+ scar-repair
8157
+ scarpe air
8158
+ scarpe hogan
8159
+ scarpe italia
8160
+ scarpe mbt
8161
+ scarpe supra
8162
+ scarpe-air
8163
+ scarpe-basket
8164
+ scarpe-hogan
8165
+ scarpe-italia
8166
+ scarpe-mbt
8167
+ scarpe-supra
8168
+ scarpebasket
8169
+ scarpehogan
8170
+ scarpeitalia
8171
+ scarrepair
8172
+ schlgsseldienste
8173
+ schlüsseldienste
8174
+ schoenen dsquared
8175
+ schoenen-dsquared
8176
+ schoenendsquared
8177
+ school.a
8178
+ schuhe puma
8179
+ schuhe-puma
8180
+ schuhepuma
8181
+ sciatica pain
8182
+ scontati
8183
+ scoriescod
8184
+ scott wing
8185
+ scott-wing
8186
+ scottwing
8187
+ scrapebox
8188
+ seaddons
8189
+ seahawks jersey
8190
+ seahawks-jersey
8191
+ seahawksjersey
8192
+ search-engine-opt
8193
+ searchengine-opt
8194
+ searchengine.
8195
+ searchengineoptimiz
8196
+ seawaypab
8197
+ secondgrade
8198
+ secret advantage
8199
+ secret beautiful
8200
+ secret generous
8201
+ secret-advantage
8202
+ secret-beautiful
8203
+ secret-generous
8204
+ secret.co
8205
+ secretadvantage
8206
+ secretbeautiful
8207
+ secretgenerous
8208
+ security-for
8209
+ seek man
8210
+ seek men
8211
+ seek wom
8212
+ seek-man
8213
+ seek-men
8214
+ seek-wom
8215
+ seeking man
8216
+ seeking men
8217
+ seeking wom
8218
+ seeking-man
8219
+ seeking-men
8220
+ seeking-wom
8221
+ seekingman
8222
+ seekingmen
8223
+ seekingwom
8224
+ seekman
8225
+ seekmen
8226
+ seekwom
8227
+ seeming vexation
8228
+ seeming-vexation
8229
+ seikomise
8230
+ seks.ru
8231
+ sell-now
8232
+ sellnow
8233
+ send earning
8234
+ send-earning
8235
+ sendflowers
8236
+ sensual massage
8237
+ sensual-massage
8238
+ sentient-health
8239
+ sentienthealth
8240
+ senuke vps
8241
+ senuke-vps
8242
+ senukevps
8243
+ seo comp
8244
+ seo gig
8245
+ seo vps
8246
+ seo_
8247
+ seo-
8248
+ seo,
8249
+ seo.
8250
+ seoaddon
8251
+ seoagenc
8252
+ seohost
8253
+ seopick
8254
+ seoplugin
8255
+ seotool
8256
+ seovps
8257
+ seowith
8258
+ seriously entice
8259
+ seriously-entice
8260
+ serravalle outlet
8261
+ serravalle-outlet
8262
+ serravalleoutlet
8263
+ serrurier http
8264
+ serrurier marseille
8265
+ serrurier paris
8266
+ serrurier-marseille
8267
+ serrurier-paris
8268
+ sertraline
8269
+ server 2007
8270
+ server 2008
8271
+ services/services
8272
+ serwis
8273
+ settings1
8274
+ settings2
8275
+ settings3
8276
+ settlement cash
8277
+ settlement-cash
8278
+ sex advice
8279
+ sex-advice
8280
+ sex-blog
8281
+ sex-cam
8282
+ sex-game
8283
+ sex-shop
8284
+ sex-tape
8285
+ sex-toy
8286
+ sex-tube
8287
+ sex-web
8288
+ sex.htm
8289
+ sexadvice
8290
+ sexblog
8291
+ sexcam
8292
+ sexdate
8293
+ sexdating
8294
+ sexelist
8295
+ sexero
8296
+ sexgame
8297
+ sexo mon
8298
+ sexo-mon
8299
+ sexomon
8300
+ sexscandal
8301
+ sexshop
8302
+ sextape
8303
+ sextoy
8304
+ sextube
8305
+ sexual fantas
8306
+ sexual moment
8307
+ sexual-fantas
8308
+ sexual-moment
8309
+ sexualfantas
8310
+ sexweb
8311
+ sexy.co
8312
+ sgames.co
8313
+ shanghai-escort
8314
+ shanghai-massage
8315
+ shanghaiescort
8316
+ shanghaimassage
8317
+ shanrig
8318
+ shared site
8319
+ shed-fat
8320
+ shemale.
8321
+ shirt cease
8322
+ shirt-cease
8323
+ shoe dior
8324
+ shoe online
8325
+ shoe out
8326
+ shoe promo
8327
+ shoe-cloth
8328
+ shoe-dior
8329
+ shoe-japan
8330
+ shoe-online
8331
+ shoe-out
8332
+ shoe-promo
8333
+ shoe.asp
8334
+ shoecloth
8335
+ shoejapan
8336
+ shoejp.co
8337
+ shoeonline
8338
+ shoeout
8339
+ shoeoutlet
8340
+ shoes dior
8341
+ shoes mbt
8342
+ shoes online
8343
+ shoes out
8344
+ shoes-2014
8345
+ shoes-cheap
8346
+ shoes-cloth
8347
+ shoes-dior
8348
+ shoes-japan
8349
+ shoes-mbt
8350
+ shoes-on-sale
8351
+ shoes-online
8352
+ shoes-out
8353
+ shoes.asp
8354
+ shoes+for+men
8355
+ shoes+men
8356
+ shoes+women
8357
+ shoesale
8358
+ shoescloth
8359
+ shoesjapan
8360
+ shoeskan
8361
+ shoesmart
8362
+ shoesmbt
8363
+ shoesonline
8364
+ shoesonsale
8365
+ shoesout
8366
+ shoesoutlet
8367
+ shoessale
8368
+ shoestore
8369
+ shoesuk
8370
+ shoesus
8371
+ shoeuk
8372
+ shoot-tequila
8373
+ shop online
8374
+ shop-japan.co
8375
+ shop-nfl
8376
+ shop-now
8377
+ shop-online
8378
+ shop-pin
8379
+ shop.asia
8380
+ shopboots
8381
+ shopent.ru
8382
+ shopg2bags
8383
+ shopjapan.co
8384
+ shopjp
8385
+ shopnfl
8386
+ shopnow
8387
+ shopof
8388
+ shoponline
8389
+ shopping site
8390
+ shopping-ugg
8391
+ shopping+
8392
+ shopping24
8393
+ shoppingcenter.co
8394
+ shoppingugg
8395
+ shopuk
8396
+ shopus.co
8397
+ short ugg
8398
+ short-ugg
8399
+ shorttermloan
8400
+ shortugg
8401
+ should http
8402
+ shoulder tote
8403
+ shoulder-tote
8404
+ shouldertote
8405
+ show_
8406
+ shownews.
8407
+ showtopic
8408
+ si.lv.e.r.w.are
8409
+ sieg heil
8410
+ sieg-heil
8411
+ siege hack
8412
+ siege-hack
8413
+ siegheil
8414
+ sign-zodiac
8415
+ signed-jersey
8416
+ signifiant
8417
+ significant infos
8418
+ significant-infos
8419
+ signozodiac
8420
+ signzodiac
8421
+ silagra
8422
+ silberbarren
8423
+ sildenafil
8424
+ silver-and-gold
8425
+ silver-ingot
8426
+ silver-jewelry
8427
+ silveringot
8428
+ silverjewelry
8429
+ sim-only
8430
+ simply shared
8431
+ simply-shared
8432
+ sinequan
8433
+ singapore.htm
8434
+ site backup
8435
+ site link
8436
+ site official
8437
+ site position
8438
+ site traffic
8439
+ site-backup
8440
+ site-google
8441
+ site-link
8442
+ site-official
8443
+ site-position
8444
+ site-traffic
8445
+ site.co
8446
+ site.in
8447
+ site24
8448
+ sitecode
8449
+ sitelink
8450
+ sitemap
8451
+ sites24
8452
+ sito ufficiale
8453
+ sito-ufficiale
8454
+ siutpd
8455
+ sizegenetic
8456
+ skapa grupp
8457
+ skapa-grupp
8458
+ skapagrupp
8459
+ skelaxin
8460
+ skin pigment
8461
+ skin_pigment
8462
+ skin-pigment
8463
+ skincare-work
8464
+ skincarework
8465
+ skip-trace
8466
+ skip-tracing
8467
+ skjønnhetsprodukter
8468
+ sklep
8469
+ sklepy
8470
+ skor-rea
8471
+ skorrea
8472
+ skup-aut
8473
+ skup,aut
8474
+ sledge baseball
8475
+ sledge bat
8476
+ sledge-baseball
8477
+ sledge-bat
8478
+ slimpill
8479
+ slimup
8480
+ slongchamp
8481
+ slot machine
8482
+ slot-machine
8483
+ slotmachine
8484
+ smallbusinessplan
8485
+ smart-drug
8486
+ smartdrug
8487
+ smeoone
8488
+ smith soldes
8489
+ smith-soldes
8490
+ smithsoldes
8491
+ smokingnews
8492
+ sms grupp
8493
+ sms-grupp
8494
+ smsgrupp
8495
+ snapbacks
8496
+ sneaker.asp
8497
+ sneakerchef
8498
+ sneakerjapan
8499
+ sneakerjp
8500
+ sneakers retail
8501
+ sneakers-retail
8502
+ sneakers.asp
8503
+ sneakers24
8504
+ sneakersretail
8505
+ snipurl.com
8506
+ snism
8507
+ social-bookmark
8508
+ socialbookmark
8509
+ socialengine
8510
+ socialite.
8511
+ socialnetworkbuzz
8512
+ socialnetworksbuzz
8513
+ societys
8514
+ soeasy
8515
+ soft-secrets
8516
+ softsecrets
8517
+ software-secret
8518
+ software.in
8519
+ softwaresecret
8520
+ sohbet
8521
+ sold-out
8522
+ solde canad
8523
+ solde-canad
8524
+ soldecanad
8525
+ soldes louboutin
8526
+ soldes ralph
8527
+ soldes-louboutin
8528
+ soldes-ralph
8529
+ soldes.co
8530
+ soldes<
8531
+ soldeslouboutin
8532
+ soleil ray
8533
+ soleil-ray
8534
+ soleilray
8535
+ solução
8536
+ solutioninc
8537
+ solutionsinc
8538
+ sonicsearch
8539
+ sooemne
8540
+ soup.io/post
8541
+ sozedde.co
8542
+ sp1 key
8543
+ sp1-key
8544
+ spaccio gucci
8545
+ spaccio woolrich
8546
+ spaccio-gucci
8547
+ spaccio-woolrich
8548
+ spacciowoolrich
8549
+ spade diaper
8550
+ spade-diaper
8551
+ spam response
8552
+ spam-response
8553
+ spammer spam
8554
+ sparkle ugg
8555
+ sparkle-ugg
8556
+ sparkleugg
8557
+ special-offer
8558
+ specialty-transfer
8559
+ specialtytransfer
8560
+ specific gift
8561
+ specific-gift
8562
+ spedified
8563
+ speed-loan
8564
+ speedloan
8565
+ speedy-product
8566
+ spip.php
8567
+ splendid department
8568
+ splendid-department
8569
+ sponsoring secret
8570
+ sponsoring-secret
8571
+ sponsoringsecret
8572
+ sportbikepart
8573
+ sportbook
8574
+ sportsbet
8575
+ sportsbook
8576
+ sportsfanshop
8577
+ sportsfanstore
8578
+ sportsgear
8579
+ sportsjersey
8580
+ sprinkler tune
8581
+ sprinkler-tune
8582
+ sprzedaz
8583
+ spyder-jacket
8584
+ spyder-ski
8585
+ spyderjackets
8586
+ spyderski
8587
+ spyware
8588
+ squidoo.co
8589
+ ssory
8590
+ starsunglass
8591
+ state-of-the-art
8592
+ statuscode
8593
+ stazhirovka
8594
+ steelersfan
8595
+ stendra
8596
+ stevewynnloan
8597
+ stig hollister
8598
+ stig online
8599
+ stig-hollister
8600
+ stig-online
8601
+ stighollister
8602
+ stigonline
8603
+ stimulacion sex
8604
+ stimulacion-sex
8605
+ stivale timberland
8606
+ stivale-timberland
8607
+ stivaletimberland
8608
+ stivali timberland
8609
+ stivali-timberland
8610
+ stivalitimberland
8611
+ stodiobeat
8612
+ stodiosbeat
8613
+ stone japan
8614
+ stone-japan
8615
+ stonejapan
8616
+ stop-smoking
8617
+ store austr
8618
+ store gucci
8619
+ store out
8620
+ store-gucci
8621
+ store-out
8622
+ store-service
8623
+ store.htm
8624
+ store.org
8625
+ storegucci
8626
+ storejp
8627
+ storeoutlet
8628
+ stosunek
8629
+ stoxymom
8630
+ straightface
8631
+ strategies-for
8632
+ strategy-for
8633
+ stratificat.
8634
+ strattera
8635
+ stromectol
8636
+ studiobeat
8637
+ studiosbeat
8638
+ stumbledupon
8639
+ stumpmaster
8640
+ stunningq
8641
+ style mbt
8642
+ style-mbt
8643
+ styledkitchen
8644
+ stylembt
8645
+ styleshq
8646
+ stylevip
8647
+ stylomontblanc
8648
+ stylowe
8649
+ subject=
8650
+ succeed-online
8651
+ success you
8652
+ success-you
8653
+ successful blog
8654
+ successful-blog
8655
+ sucesso.co
8656
+ sucette
8657
+ suggested-website
8658
+ sumatriptan
8659
+ summer coach
8660
+ summer-coach
8661
+ sunchannel
8662
+ sunglass cheap
8663
+ sunglass out
8664
+ sunglassau
8665
+ sunglasses cheap
8666
+ sunglasses out
8667
+ sunglasses.us
8668
+ sunglassesau
8669
+ sunglassesok
8670
+ sunglassesuk
8671
+ sunglassok
8672
+ sunglassuk
8673
+ sunrize
8674
+ superarticle
8675
+ superheroz
8676
+ superstar class
8677
+ superstar-class
8678
+ superstarclass
8679
+ supply_
8680
+ supra shoe
8681
+ supra-shoe
8682
+ suprashoe
8683
+ suprax
8684
+ supreme-essay
8685
+ supremeessay
8686
+ surf online
8687
+ surf to
8688
+ surf-online
8689
+ surf-to
8690
+ surfing online
8691
+ surfing-online
8692
+ surprisezone
8693
+ suwa³ki
8694
+ svente enligne
8695
+ svente-enligne
8696
+ sventeenligne
8697
+ swarovski
8698
+ swarovskijapan
8699
+ swarovskijp
8700
+ swiss-replica
8701
+ sword trade
8702
+ sword-trade
8703
+ swords trade
8704
+ swords-trade
8705
+ swordstrade
8706
+ swordtrade
8707
+ syaneru
8708
+ symptom-med
8709
+ symptommed
8710
+ symptoms-med
8711
+ symptomsmed
8712
+ system-pro
8713
+ system-review
8714
+ tabaki
8715
+ tadalafil
8716
+ tadapox
8717
+ tag_heuer
8718
+ tag/event
8719
+ taille costume
8720
+ taille-costume
8721
+ taken gravely
8722
+ taken-gravely
8723
+ takenwith
8724
+ takje care
8725
+ takje-care
8726
+ tamiflu
8727
+ tamoxifen
8728
+ tamsulosin
8729
+ tanger outlet
8730
+ tanger-outlet
8731
+ tapicerowane
8732
+ targeted traffic
8733
+ targeted visit
8734
+ targeted visitor
8735
+ targeted-traffic
8736
+ targeted-visit
8737
+ targetedtraffic
8738
+ targetedvisit
8739
+ targetted traffic
8740
+ targetted visit
8741
+ targetted-traffic
8742
+ targetted-visit
8743
+ targettedtraffic
8744
+ targettedvisit
8745
+ tarif-malin
8746
+ tarifmalin
8747
+ tariki shoe
8748
+ tariki-shoe
8749
+ tarikishoe
8750
+ tarot divin
8751
+ tarot-divin
8752
+ tasche longchamp
8753
+ tasche-longchamp
8754
+ taschelongchamp
8755
+ taschen longchamp
8756
+ taschen-longchamp
8757
+ taschenlongchamp
8758
+ tastegood.co
8759
+ tattoo-tip
8760
+ tattootip
8761
+ tax-book
8762
+ tax-debt
8763
+ taxbook
8764
+ taxdebt
8765
+ teach-you-every
8766
+ teamproshop
8767
+ teen female
8768
+ teen porn
8769
+ teen sex
8770
+ teen-female
8771
+ teen-porn
8772
+ teen-sex
8773
+ teenage female
8774
+ teenage-female
8775
+ teenaged female
8776
+ teenaged-female
8777
+ teeniepant
8778
+ teenporn
8779
+ teensex
8780
+ teenwebcam
8781
+ tees hollister
8782
+ tees-hollister
8783
+ teeshollister
8784
+ tegs:
8785
+ telephone gratuit
8786
+ telephone-gratuit
8787
+ telepon-
8788
+ template.co
8789
+ templates.co
8790
+ templerun-
8791
+ templerun1
8792
+ tenormin
8793
+ term dinner
8794
+ term loan
8795
+ term-dinner
8796
+ termopane
8797
+ test.ca
8798
+ test.in
8799
+ test.tumblr
8800
+ test@
8801
+ test1.
8802
+ testosterone-boost
8803
+ testrun
8804
+ testuser
8805
+ tetracycline
8806
+ texans-jersey
8807
+ texansjersey
8808
+ tgf@
8809
+ thailove
8810
+ thanks.i
8811
+ that isnt
8812
+ that-isnt
8813
+ thatover
8814
+ thatprofit
8815
+ the -notify
8816
+ the pokie
8817
+ the the
8818
+ the threading
8819
+ the_best
8820
+ the-benefits-of
8821
+ the-best-treatment
8822
+ the-diet
8823
+ the-hypothyroid
8824
+ the-latest-
8825
+ the-most-common
8826
+ the-most-detail
8827
+ the-pokie
8828
+ the-right-way
8829
+ the-the
8830
+ the-threading
8831
+ theaverage
8832
+ thebestis
8833
+ thebestprice
8834
+ thedevelop
8835
+ theeasy
8836
+ theguest
8837
+ thehypothyroid
8838
+ theme sale
8839
+ theme-basic
8840
+ theme-generat
8841
+ theme-sale
8842
+ themebasic
8843
+ themegenerat
8844
+ themes sale
8845
+ themes-for-windows
8846
+ themes-sale
8847
+ themesforwindows
8848
+ therealest
8849
+ thes good
8850
+ thespacious
8851
+ thetopdog
8852
+ theyll
8853
+ thhis
8854
+ things-consume
8855
+ things-we-love
8856
+ this blog
8857
+ this review
8858
+ this weblog
8859
+ this website
8860
+ this-blog
8861
+ this-review
8862
+ this-weblog
8863
+ this-website
8864
+ thisjourney
8865
+ thm.htm
8866
+ thomas sabot
8867
+ thomas-sabot
8868
+ thomasfat
8869
+ thomassabo-sale
8870
+ thomassabo-uk
8871
+ thomassabosale
8872
+ thomassabouk
8873
+ thportfol
8874
+ thumb.jpeg
8875
+ thumb.jpg
8876
+ thumb.png
8877
+ thyromine
8878
+ tɦey
8879
+ ticket http
8880
+ tickets http
8881
+ tier business
8882
+ tier-business
8883
+ tiffany france
8884
+ tiffany jewel
8885
+ tiffany ring
8886
+ tiffany-france
8887
+ tiffany-jewel
8888
+ tiffany-out
8889
+ tiffany-ring
8890
+ tiffanyjewel
8891
+ tiffanyout
8892
+ tiffanyring
8893
+ tiffanysale
8894
+ tiffiny
8895
+ tihnikng
8896
+ tiki-index
8897
+ timberland cheap
8898
+ timberland out
8899
+ timberland pas
8900
+ timberland saldi
8901
+ timberland shoe
8902
+ timberland uom
8903
+ timberland-cheap
8904
+ timberland-out
8905
+ timberland-pas
8906
+ timberland-saldi
8907
+ timberland-uom
8908
+ timberland1
8909
+ timberland2
8910
+ timberlandboot
8911
+ timberlandcheap
8912
+ timberlandout
8913
+ timberlandpas
8914
+ timberlandsaldi
8915
+ timberlanduom
8916
+ time-synchronisation.co
8917
+ times(with
8918
+ timesamsonss
8919
+ timeshare
8920
+ tingenieur
8921
+ tiny.cc
8922
+ tinytowtimmy.co
8923
+ tinyurl.com
8924
+ tipblog
8925
+ tips-for-
8926
+ tips-to-start
8927
+ tips.info
8928
+ tipsblog
8929
+ tipsof
8930
+ tire-discount
8931
+ tire-wholesale
8932
+ tirediscount
8933
+ tires-discount
8934
+ tires-wholesale
8935
+ tiresdiscount
8936
+ tireswholesale
8937
+ tirewholesale
8938
+ tit-pad
8939
+ titans merch
8940
+ titans-merch
8941
+ titansmerch
8942
+ tizanidine
8943
+ tms-shoe
8944
+ tmsshoe
8945
+ tnf-sale
8946
+ tnfsale
8947
+ toasterovensnow
8948
+ today/article
8949
+ todsjapan
8950
+ todsjp
8951
+ toeshoe.co
8952
+ toeshoes.co
8953
+ tofranil
8954
+ toile vanessa
8955
+ toile-vanessa
8956
+ toilevanessa
8957
+ tojp.co
8958
+ token generat
8959
+ token hack
8960
+ token-generat
8961
+ token-hack
8962
+ tokyo-lv
8963
+ told u?
8964
+ toms price
8965
+ toms shoe
8966
+ toms women
8967
+ toms-cheap
8968
+ toms-price
8969
+ toms-shoe
8970
+ toms-women
8971
+ tomscheap
8972
+ tomsforsale
8973
+ tomsout
8974
+ tomsshoe
8975
+ tomsshoes
8976
+ tomswomen
8977
+ top tier
8978
+ top-forum
8979
+ top-list
8980
+ top-muscle
8981
+ top-rank
8982
+ top-search
8983
+ top-site
8984
+ top-tier
8985
+ topamax
8986
+ topcontractor
8987
+ topforum
8988
+ topiramate
8989
+ toplist
8990
+ topman123
8991
+ topmuscle
8992
+ toprank
8993
+ topsearch
8994
+ topseo
8995
+ topsite
8996
+ topvideocon
8997
+ torrent-movie
8998
+ torrentmovie
8999
+ torrents
9000
+ torsemide
9001
+ toryburch1
9002
+ toryburch2
9003
+ toryburchflat
9004
+ toryburchten
9005
+ totaldns.in
9006
+ totalizador
9007
+ tote handbag
9008
+ tote-handbag
9009
+ totehandbag
9010
+ town|
9011
+ tr.im
9012
+ trace-service
9013
+ tracing-service
9014
+ track-phone-location
9015
+ tracking-a-phone
9016
+ trade_your
9017
+ trading-method
9018
+ trafficz
9019
+ trailer sale
9020
+ trailer-sale
9021
+ trailersale
9022
+ training-online
9023
+ training-pro
9024
+ trainingonline
9025
+ trainingpro
9026
+ traitement-des
9027
+ tramadol
9028
+ transform-vhs
9029
+ travel.pl
9030
+ traveltrip
9031
+ trazodone
9032
+ treatment.in
9033
+ trempe sous
9034
+ trempe-sous
9035
+ trening
9036
+ tresore
9037
+ tretinoin
9038
+ trickphoto
9039
+ trimethoprim
9040
+ triviatrivia
9041
+ trollapp
9042
+ true search
9043
+ truly very
9044
+ truly-very
9045
+ truthabout
9046
+ try-these
9047
+ tubee.tv
9048
+ tucholskie
9049
+ tumi1
9050
+ tumi2
9051
+ tummy tuck
9052
+ tummy-tuck
9053
+ tummytuck
9054
+ turbo-vac
9055
+ turbosprezar
9056
+ turystyka
9057
+ tutorial.htm
9058
+ tutoringand
9059
+ tvturn
9060
+ tworzenie
9061
+ uauaua
9062
+ ubezpieczenia
9063
+ ubirkin
9064
+ ucoz.co
9065
+ ucoz.ru
9066
+ ufficiales
9067
+ ugboos
9068
+ ugbos
9069
+ ugg 3
9070
+ ugg ad
9071
+ ugg animal
9072
+ ugg austr
9073
+ ugg bailey
9074
+ ugg bamsestøvler
9075
+ ugg bebe
9076
+ ugg black
9077
+ ugg boot
9078
+ ugg botte
9079
+ ugg brown
9080
+ ugg brux
9081
+ ugg cheap
9082
+ ugg class
9083
+ ugg dakota
9084
+ ugg elsey
9085
+ ugg enfant
9086
+ ugg femme
9087
+ ugg fox
9088
+ ugg france
9089
+ ugg glove
9090
+ ugg hobo
9091
+ ugg hot
9092
+ ugg ken
9093
+ ugg mocha
9094
+ ugg noir
9095
+ ugg out
9096
+ ugg paris
9097
+ ugg pas
9098
+ ugg pascher
9099
+ ugg sale
9100
+ ugg shear
9101
+ ugg shoe
9102
+ ugg short
9103
+ ugg silver
9104
+ ugg sold
9105
+ ugg støvler
9106
+ ugg style
9107
+ ugg three
9108
+ ugg turn
9109
+ ugg wom
9110
+ ugg-3
9111
+ ugg-ad
9112
+ ugg-animal
9113
+ ugg-bailey
9114
+ ugg-bamsestøvler
9115
+ ugg-bebe
9116
+ ugg-best
9117
+ ugg-black
9118
+ ugg-boot
9119
+ ugg-botte
9120
+ ugg-brown
9121
+ ugg-brux
9122
+ ugg-cheap
9123
+ ugg-class
9124
+ ugg-comfort
9125
+ ugg-elsey
9126
+ ugg-enfant
9127
+ ugg-femme
9128
+ ugg-for
9129
+ ugg-fox
9130
+ ugg-france
9131
+ ugg-glove
9132
+ ugg-hobo
9133
+ ugg-hot
9134
+ ugg-ken
9135
+ ugg-mocha
9136
+ ugg-noir
9137
+ ugg-official
9138
+ ugg-on
9139
+ ugg-out
9140
+ ugg-paris
9141
+ ugg-pas
9142
+ ugg-pascher
9143
+ ugg-sale
9144
+ ugg-shear
9145
+ ugg-shoe
9146
+ ugg-short
9147
+ ugg-silver
9148
+ ugg-site
9149
+ ugg-sold
9150
+ ugg-støvler
9151
+ ugg-style
9152
+ ugg-three
9153
+ ugg-turn
9154
+ ugg-uk
9155
+ ugg-usa
9156
+ ugg-wom
9157
+ ugg.htm
9158
+ ugg+
9159
+ ugg=
9160
+ ugg3
9161
+ uggad
9162
+ ugganimal
9163
+ uggatcanad
9164
+ uggbailey
9165
+ uggbamsestøvler
9166
+ uggbebe
9167
+ uggbest
9168
+ uggblack
9169
+ uggboo
9170
+ uggboot
9171
+ uggbos
9172
+ uggbotte
9173
+ uggbrown
9174
+ uggbrux
9175
+ uggcheap
9176
+ uggclass
9177
+ uggclog
9178
+ uggcomfort
9179
+ uggdakota
9180
+ uggelsey
9181
+ uggenfant
9182
+ uggfemme
9183
+ uggfor
9184
+ uggfox
9185
+ uggfrance
9186
+ uggglove
9187
+ ugghobo
9188
+ ugghot
9189
+ uggken
9190
+ ugglove
9191
+ uggmocha
9192
+ uggnoir
9193
+ uggofficial
9194
+ uggonline
9195
+ uggout
9196
+ uggoutlet
9197
+ uggparis
9198
+ uggpas
9199
+ uggpascher
9200
+ uggs austr
9201
+ uggs bailey
9202
+ uggs bebe
9203
+ uggs black
9204
+ uggs boot
9205
+ uggs brux
9206
+ uggs class
9207
+ uggs elsey
9208
+ uggs femme
9209
+ uggs hot
9210
+ uggs http
9211
+ uggs kopen
9212
+ uggs mocha
9213
+ uggs neder
9214
+ uggs noir
9215
+ uggs out
9216
+ uggs paris
9217
+ uggs pas
9218
+ uggs pascher
9219
+ uggs sale
9220
+ uggs shoe
9221
+ uggs silver
9222
+ uggs sold
9223
+ uggs ugly
9224
+ uggs uitverkoop
9225
+ uggs wom
9226
+ uggs-austr
9227
+ uggs-bailey
9228
+ uggs-bebe
9229
+ uggs-black
9230
+ uggs-boot
9231
+ uggs-brux
9232
+ uggs-class
9233
+ uggs-elsey
9234
+ uggs-femme
9235
+ uggs-for
9236
+ uggs-hot
9237
+ uggs-kopen
9238
+ uggs-mocha
9239
+ uggs-neder
9240
+ uggs-noir
9241
+ uggs-on
9242
+ uggs-out
9243
+ uggs-paris
9244
+ uggs-pas
9245
+ uggs-pascher
9246
+ uggs-sale
9247
+ uggs-shoe
9248
+ uggs-silver
9249
+ uggs-site
9250
+ uggs-sold
9251
+ uggs-ugly
9252
+ uggs-uitverkoop
9253
+ uggs-uk
9254
+ uggs-usa
9255
+ uggs-wom
9256
+ uggs.co
9257
+ uggsale
9258
+ uggsaustr
9259
+ uggsbailey
9260
+ uggsbay
9261
+ uggsbebe
9262
+ uggsblack
9263
+ uggsboot
9264
+ uggsbrux
9265
+ uggscheap
9266
+ uggsclass
9267
+ uggselsey
9268
+ uggsfemme
9269
+ uggsfor
9270
+ uggshear
9271
+ uggshoe
9272
+ uggshort
9273
+ uggshot
9274
+ uggsilver
9275
+ uggsite
9276
+ uggskopen
9277
+ uggslove
9278
+ uggsmocha
9279
+ uggsneder
9280
+ uggsnoir
9281
+ uggsold
9282
+ uggsonline
9283
+ uggsout
9284
+ uggsoutlet
9285
+ uggsparis
9286
+ uggspas
9287
+ uggspascher
9288
+ uggss
9289
+ uggssilver
9290
+ uggstøvler
9291
+ uggstyle
9292
+ uggsugly
9293
+ uggsuitverkoop
9294
+ uggsusa
9295
+ uggsustra
9296
+ uggswom
9297
+ uggthree
9298
+ uggturn
9299
+ uggusa
9300
+ uggustra
9301
+ uggwom
9302
+ uhren out
9303
+ uk out
9304
+ uk sale
9305
+ uk-handbag
9306
+ uk-loan
9307
+ uk-mall
9308
+ uk-mart
9309
+ uk-out
9310
+ uk-sale
9311
+ uk.co.
9312
+ uk.webeden
9313
+ uk/mulberry
9314
+ uk/prada
9315
+ ukclsale
9316
+ ukgardenhouses
9317
+ ukhandbag
9318
+ ukloan
9319
+ ukmall
9320
+ ukmart
9321
+ ukonline
9322
+ ukoutlet
9323
+ uksale
9324
+ uksonline
9325
+ ukugg
9326
+ ukvip
9327
+ ulkotours
9328
+ ultimate microsoft
9329
+ ultimate sp1
9330
+ ultimate-microsoft
9331
+ ultimate-sp1
9332
+ ultimate-tab
9333
+ ultimatemicrosoft
9334
+ ultimatetab
9335
+ ultram
9336
+ umschuldung
9337
+ under pant
9338
+ under-pant
9339
+ underpant
9340
+ underthe
9341
+ une moncler
9342
+ une-moncler
9343
+ unemoncler
9344
+ unitedidesign
9345
+ universal-key
9346
+ unknown.ru
9347
+ unknown@
9348
+ unlock iphone
9349
+ unlock-iphone
9350
+ unlock-mobile
9351
+ unlock-phone
9352
+ unlockiphone
9353
+ unlockmobile
9354
+ unlockphone
9355
+ unwanted-hair
9356
+ unwantedhair
9357
+ uomo adidas
9358
+ uomo dsquared
9359
+ uomo man
9360
+ uomo moncler
9361
+ uomo timberland
9362
+ uomo-adidas
9363
+ uomo-dsquared
9364
+ uomo-man
9365
+ uomo-moncler
9366
+ uomo-short
9367
+ uomo-timberland
9368
+ uomoadidas
9369
+ uomoman
9370
+ uomomoncler
9371
+ uomotimberland
9372
+ up-to-date
9373
+ upgrade key
9374
+ upgrade-key
9375
+ upgradekey
9376
+ upload_
9377
+ upseseglype
9378
+ urlacher jersey
9379
+ urlacher-jersey
9380
+ urlacherjersey
9381
+ urls2
9382
+ urlstatusgo.htm
9383
+ uroda
9384
+ us/profile
9385
+ usa-best
9386
+ usabest
9387
+ user_
9388
+ user/profile
9389
+ user/view
9390
+ userinfo
9391
+ usualdiscuss
9392
+ usually relative
9393
+ usually-relative
9394
+ ut.ag/
9395
+ utilized use
9396
+ uustore
9397
+ uy/image
9398
+ valise louis
9399
+ valise-louis
9400
+ valiselouis
9401
+ valium
9402
+ valtrex
9403
+ valueble
9404
+ vanessa-bruno-sac
9405
+ vanessabrunosac
9406
+ vaporizer pen
9407
+ varabella
9408
+ vardenafil
9409
+ vegas hotel
9410
+ vegas show
9411
+ vegas social
9412
+ vegas-hotel
9413
+ vegas-show
9414
+ vegas-social
9415
+ vendita
9416
+ vendorlock
9417
+ venlafaxine
9418
+ ventolin inhale
9419
+ ventures impart
9420
+ ventures note
9421
+ ventures pleasant
9422
+ ventures profit
9423
+ ventures shape
9424
+ ventures-impart
9425
+ ventures-note
9426
+ ventures-pleasant
9427
+ ventures-profit
9428
+ ventures-shape
9429
+ versace-japan
9430
+ versacejapan
9431
+ versicherungsmakler
9432
+ very disconcertingly
9433
+ very-disconcertingly
9434
+ very}
9435
+ veste moncler
9436
+ veste-moncler
9437
+ vestemoncler
9438
+ vestidos
9439
+ veston class
9440
+ veston-class
9441
+ vestonclass
9442
+ vetement-femme
9443
+ vetement-homme
9444
+ veterinarnaya
9445
+ vhs-to-digital
9446
+ via-internet
9447
+ viagera
9448
+ viagra
9449
+ vicodin
9450
+ video sport
9451
+ video-magnif
9452
+ video-pokie
9453
+ video-sport
9454
+ video.htm
9455
+ videochat
9456
+ videogamedesign
9457
+ videomagnif
9458
+ videopokie
9459
+ videos.htm
9460
+ videosport
9461
+ vidios
9462
+ viencare
9463
+ view_
9464
+ view-article
9465
+ view-blog
9466
+ view-entry
9467
+ viewarticle
9468
+ viewblog
9469
+ viewentry
9470
+ viewlink
9471
+ viewpag
9472
+ viewtopic
9473
+ vigara
9474
+ vigrx
9475
+ vimax
9476
+ vinder burberry
9477
+ vinder-burberry
9478
+ vinderburberry
9479
+ vinhobrasil-
9480
+ vinhobrasil.
9481
+ vintage-erotic
9482
+ vinterjakker
9483
+ vipgirl
9484
+ viramune
9485
+ virtual sex
9486
+ virtual-sex
9487
+ virus answer
9488
+ virus hoax
9489
+ virus infеct
9490
+ virus remov
9491
+ virus secur
9492
+ virus-answer
9493
+ virus-hoax
9494
+ virus-infеct
9495
+ virus-remov
9496
+ virus-secur
9497
+ virusanswer
9498
+ virushoax
9499
+ virusinfеct
9500
+ virusremov
9501
+ virussecur
9502
+ visit homepage
9503
+ visit web
9504
+ visit-homepage
9505
+ visit-web
9506
+ visitant
9507
+ visitor/day
9508
+ visitors/day
9509
+ vitalikor
9510
+ vitamin-for
9511
+ vitaminfor
9512
+ vitamins-for
9513
+ vitaminsfor
9514
+ vitamix
9515
+ vitrine
9516
+ vivekkunwar
9517
+ vivier ballerine
9518
+ vivier-ballerine
9519
+ vivierballerine
9520
+ vivotab
9521
+ vogue toms
9522
+ vogue-toms
9523
+ voguetoms
9524
+ voyance amour
9525
+ voyance couple
9526
+ voyance gratuite
9527
+ voyance http
9528
+ voyance-amour
9529
+ voyance-couple
9530
+ voyance-gratuite
9531
+ voyance<
9532
+ vuitton austr
9533
+ vuitton bag
9534
+ vuitton belt
9535
+ vuitton black
9536
+ vuitton bracelet
9537
+ vuitton cig
9538
+ vuitton damier
9539
+ vuitton deutsch
9540
+ vuitton factory
9541
+ vuitton fanny
9542
+ vuitton fashion
9543
+ vuitton france
9544
+ vuitton fx
9545
+ vuitton glass
9546
+ vuitton hand
9547
+ vuitton hard
9548
+ vuitton men
9549
+ vuitton online
9550
+ vuitton out
9551
+ vuitton pas
9552
+ vuitton purse
9553
+ vuitton replica
9554
+ vuitton sac
9555
+ vuitton shoe
9556
+ vuitton sold
9557
+ vuitton speed
9558
+ vuitton taschen
9559
+ vuitton wallet
9560
+ vuitton wholesale
9561
+ vuitton women
9562
+ vuitton-bag
9563
+ vuitton-black
9564
+ vuitton-bracelet
9565
+ vuitton-cig
9566
+ vuitton-damier
9567
+ vuitton-fanny
9568
+ vuitton-fashion
9569
+ vuitton-glass
9570
+ vuitton-men
9571
+ vuitton-pas
9572
+ vuitton-purse
9573
+ vuitton-replica
9574
+ vuitton-shoe
9575
+ vuitton-sold
9576
+ vuitton-speed
9577
+ vuitton-uk
9578
+ vuitton-usa
9579
+ vuitton-wallet
9580
+ vuitton-wholesale
9581
+ vuitton-women
9582
+ vuitton<
9583
+ vuittonbag
9584
+ vuittoncig
9585
+ vuittondamier
9586
+ vuittonfanny
9587
+ vuittonfashion
9588
+ vuittonglass
9589
+ vuittononline
9590
+ vuittonpas
9591
+ vuittonpurse
9592
+ vuittonreplica
9593
+ vuittonsac
9594
+ vuittonsold
9595
+ vuittonspeed
9596
+ vuittonuk
9597
+ vuittonusa
9598
+ vuittonwallet
9599
+ vuittonwholesale
9600
+ wakka=
9601
+ wallet out
9602
+ wallet-out
9603
+ walletout
9604
+ wallinside
9605
+ walmartbuy
9606
+ walmartmail
9607
+ wang bag
9608
+ wang-bag
9609
+ wangbag
9610
+ wantsand
9611
+ warcraftguide
9612
+ ware-crack
9613
+ warecrack
9614
+ warehouse.net
9615
+ warehouse.org
9616
+ warehouse.pl
9617
+ warehouse.ru
9618
+ warehouse.us
9619
+ warepics
9620
+ warmjp
9621
+ warszawa
9622
+ wasbusiness
9623
+ watch video
9624
+ watch-quartz
9625
+ watch-replica
9626
+ watch-seiko
9627
+ watch-video
9628
+ watches-quartz
9629
+ watchesquartz
9630
+ watchhoshi
9631
+ watchquartz
9632
+ watchreplica
9633
+ watchseiko
9634
+ water-weight
9635
+ way-to-enjoy
9636
+ wayfarer baratas
9637
+ wayfarer glass
9638
+ wayfarer-baratas
9639
+ wayfarer-glass
9640
+ wayfarerglass
9641
+ wdmypass
9642
+ we-are-your
9643
+ weave-hair
9644
+ weavehair
9645
+ web anal
9646
+ web blog
9647
+ web owner
9648
+ web people
9649
+ web promo
9650
+ web_log
9651
+ web-anal
9652
+ web-blog
9653
+ web-hosting
9654
+ web-log
9655
+ web-owner
9656
+ web-people
9657
+ web-promo
9658
+ web-site
9659
+ web-solution
9660
+ web-traffic
9661
+ web-view
9662
+ web/icon
9663
+ web/index
9664
+ webanal
9665
+ webblog
9666
+ webcambabe
9667
+ webcamsex
9668
+ webdesign.co
9669
+ webfarma
9670
+ webhosting
9671
+ weblink
9672
+ weblog site
9673
+ weblog-site
9674
+ weblog}
9675
+ weblogto
9676
+ webmaster
9677
+ webnode.cn
9678
+ webnode.co
9679
+ webnode.cz
9680
+ webnode.fr
9681
+ webnode.hu
9682
+ webnode.it
9683
+ webnode.nl
9684
+ webpag
9685
+ webpharma
9686
+ webpromo
9687
+ webpromotion
9688
+ websex
9689
+ webshop/image
9690
+ website online
9691
+ website post
9692
+ website traffic
9693
+ website usa
9694
+ website visitor
9695
+ website-online
9696
+ website-post
9697
+ website-usa
9698
+ website-visitor
9699
+ website!!
9700
+ website}
9701
+ website1
9702
+ websiteonline
9703
+ websiterecord
9704
+ websites online
9705
+ websites-online
9706
+ websitesdesign
9707
+ websitesonline
9708
+ websiteusa
9709
+ websolution
9710
+ webviewconsult
9711
+ wedding jewelry
9712
+ wedding-jewelry
9713
+ weddingdress
9714
+ week.in
9715
+ weekly.in
9716
+ weeklyincome
9717
+ weeklyprofit
9718
+ weight gain
9719
+ weight loss
9720
+ weight-gain
9721
+ weight-loss
9722
+ weight-work
9723
+ weightgain
9724
+ weightloss
9725
+ weightnatural
9726
+ welcometonginx
9727
+ wellbutrin
9728
+ weptwith
9729
+ werbegeschenke
9730
+ westwood boot
9731
+ westwood-boot
9732
+ westwoodboot
9733
+ wet pant
9734
+ wet-pant
9735
+ wetpant
9736
+ wetting pant
9737
+ wetting-pant
9738
+ wettingpant
9739
+ weusecoin
9740
+ what-we-know
9741
+ what's up,
9742
+ what’s up,
9743
+ whatll
9744
+ whats up,
9745
+ whatsapp
9746
+ wheels.co
9747
+ wheels.net
9748
+ wheels.org
9749
+ whenshe
9750
+ where buy
9751
+ where-buy
9752
+ where-to-buy
9753
+ wherebuy
9754
+ wherecani
9755
+ wheretobuy
9756
+ whichpag
9757
+ white nfl
9758
+ white-nfl
9759
+ whitehat
9760
+ whois tool
9761
+ whois-tool
9762
+ wholesale acrylic
9763
+ wholesale bag
9764
+ wholesale cheap
9765
+ wholesale china
9766
+ wholesale coach
9767
+ wholesale free
9768
+ wholesale handbag
9769
+ wholesale jersey
9770
+ wholesale jordan
9771
+ wholesale led
9772
+ wholesale nba
9773
+ wholesale north
9774
+ wholesale polo
9775
+ wholesale-acrylic
9776
+ wholesale-bag
9777
+ wholesale-cheap
9778
+ wholesale-china
9779
+ wholesale-coach
9780
+ wholesale-free
9781
+ wholesale-handbag
9782
+ wholesale-jersey
9783
+ wholesale-jordan
9784
+ wholesale-led
9785
+ wholesale-mac
9786
+ wholesale-nba
9787
+ wholesale-north
9788
+ wholesale-polo
9789
+ wholesalebag
9790
+ wholesalecheap
9791
+ wholesalechina
9792
+ wholesalecoach
9793
+ wholesalefree
9794
+ wholesalehandbag
9795
+ wholesalejersey
9796
+ wholesalejordan
9797
+ wholesaleled
9798
+ wholesalemac
9799
+ wholesalenba
9800
+ wholesalenorth
9801
+ wholesalepolo
9802
+ wholesaler-mac
9803
+ wholesalermac
9804
+ why-would-you
9805
+ widyaw
9806
+ wifi-jammer
9807
+ wifijammer
9808
+ wiki/%
9809
+ wiki/index
9810
+ wiki/user
9811
+ wikka.php
9812
+ wille bijoux
9813
+ wille solde
9814
+ wille-bijoux
9815
+ wille-solde
9816
+ willebijoux
9817
+ willesolde
9818
+ wilson jersey
9819
+ wilson-jersey
9820
+ wilsonjersey
9821
+ win7.co
9822
+ win7pro
9823
+ win8.co
9824
+ win8pro
9825
+ windows anytime
9826
+ windows-8-theme
9827
+ windows-anytime
9828
+ windows-app
9829
+ windows7key
9830
+ windows8key
9831
+ windowsanytime
9832
+ windowsphone.co
9833
+ winesickle
9834
+ wingsshop
9835
+ winter jassen
9836
+ winter-jassen
9837
+ winterjassen
9838
+ with pics
9839
+ with-pics
9840
+ without prescript
9841
+ without-invest
9842
+ without-prescript
9843
+ women makeup
9844
+ women mbt
9845
+ women nike
9846
+ women-date
9847
+ women-makeup
9848
+ women-mbt
9849
+ women-nike
9850
+ womendate
9851
+ womenmbt
9852
+ womennike
9853
+ womens bcbg
9854
+ womens boot
9855
+ womens fashion
9856
+ womens hollister
9857
+ womens nike
9858
+ womens puma
9859
+ womens shoe
9860
+ womens watch
9861
+ womens-bag
9862
+ womens-bcbg
9863
+ womens-boot
9864
+ womens-fashion
9865
+ womens-hollister
9866
+ womens-nike
9867
+ womens-puma
9868
+ womens-shoe
9869
+ womens-train
9870
+ womens-watch
9871
+ womensbcbg
9872
+ womenseekingmen
9873
+ womensnike
9874
+ womenspuma
9875
+ won webpage
9876
+ won-webpage
9877
+ wonderful article
9878
+ wonderful post
9879
+ wonderful publish
9880
+ wonderful-article
9881
+ wonderful-post
9882
+ wonderful-publish
9883
+ woodgundy.us
9884
+ woolrich bliz
9885
+ woolrich cloth
9886
+ woolrich coat
9887
+ woolrich coupon
9888
+ woolrich donn
9889
+ woolrich europe
9890
+ woolrich field
9891
+ woolrich giub
9892
+ woolrich jacket
9893
+ woolrich john
9894
+ woolrich outlet
9895
+ woolrich parka
9896
+ woolrich piumini
9897
+ woolrich scarf
9898
+ woolrich store
9899
+ woolrich uomo
9900
+ woolrich vest
9901
+ woolrich wool
9902
+ woolrich-bliz
9903
+ woolrich-cloth
9904
+ woolrich-coat
9905
+ woolrich-coupon
9906
+ woolrich-donn
9907
+ woolrich-europe
9908
+ woolrich-field
9909
+ woolrich-giub
9910
+ woolrich-jacket
9911
+ woolrich-john
9912
+ woolrich-outlet
9913
+ woolrich-parka
9914
+ woolrich-piumini
9915
+ woolrich-scarf
9916
+ woolrich-store
9917
+ woolrich-uomo
9918
+ woolrich-vest
9919
+ woolrich-wool
9920
+ woolrich.arkis
9921
+ woolrichbliz
9922
+ woolrichcloth
9923
+ woolrichcoat
9924
+ woolrichcoupon
9925
+ woolrichdonn
9926
+ woolricheurope
9927
+ woolrichfield
9928
+ woolrichgiub
9929
+ woolrichjacket
9930
+ woolrichjohn
9931
+ woolrichoutlet
9932
+ woolrichparka
9933
+ woolrichpiumini
9934
+ woolrichscarf
9935
+ woolrichstore
9936
+ woolrichuomo
9937
+ woolrichvest
9938
+ woolrichwool
9939
+ woowoo-house
9940
+ woowoo-sex
9941
+ woowoo-site
9942
+ woowoohouse
9943
+ woowoosex
9944
+ woowoosite
9945
+ wordpress web
9946
+ wordpress-theme
9947
+ wordpress-web
9948
+ wordpresstheme
9949
+ wordpressweb
9950
+ work-review
9951
+ workout-sale
9952
+ workoutsale
9953
+ workreview
9954
+ world-venture
9955
+ worlds.blog
9956
+ worldugg
9957
+ worldventure
9958
+ worldwideugg
9959
+ wow-gold
9960
+ wowo-house
9961
+ wowo-sex
9962
+ wowo-site
9963
+ wowohouse
9964
+ wowosex
9965
+ wowosite
9966
+ wp robot
9967
+ wp-pad
9968
+ wp-phone
9969
+ wp-robot
9970
+ wprobot
9971
+ wpthemegen
9972
+ wristpain
9973
+ writing-service
9974
+ writingservice
9975
+ wwellness
9976
+ www.0day
9977
+ www.1
9978
+ www.2012
9979
+ www.2013
9980
+ www.2014
9981
+ www.adults
9982
+ www.anal
9983
+ www.angel
9984
+ www.article
9985
+ www.barata
9986
+ www.barato
9987
+ www.best-
9988
+ www.brand
9989
+ www.buy
9990
+ www.canadagoose
9991
+ www.cartier-
9992
+ www.casino
9993
+ www.cellphone
9994
+ www.chanel-
9995
+ www.cheap
9996
+ www.coach-
9997
+ www.deels
9998
+ www.drdrebeat
9999
+ www.easy
10000
+ www.efinancial
10001
+ www.erotic
10002
+ www.escort
10003
+ www.everyleg
10004
+ www.everylight
10005
+ www.everypant
10006
+ www.everysock
10007
+ www.everytight
10008
+ www.fake
10009
+ www.female
10010
+ www.filmy.
10011
+ www.financ
10012
+ www.forum
10013
+ www.fot-
10014
+ www.fot.
10015
+ www.fota-
10016
+ www.fota.
10017
+ www.foteczka
10018
+ www.fotka
10019
+ www.fotki
10020
+ www.foto-
10021
+ www.foto.
10022
+ www.fotoalbum
10023
+ www.fotograf
10024
+ www.fotomania
10025
+ www.freerun
10026
+ www.fullsize
10027
+ www.gambl
10028
+ www.game
10029
+ www.gift
10030
+ www.goosepa
10031
+ www.gucci
10032
+ www.handbag
10033
+ www.hermes
10034
+ www.herveleger
10035
+ www.hot
10036
+ www.howmuch
10037
+ www.information
10038
+ www.insta
10039
+ www.instyler
10040
+ www.isabelmarant
10041
+ www.kobe
10042
+ www.lastminute
10043
+ www.lebron
10044
+ www.link
10045
+ www.lolita
10046
+ www.louboutin
10047
+ www.love
10048
+ www.lv
10049
+ www.mcm
10050
+ www.moncler
10051
+ www.mulberry
10052
+ www.newbalance
10053
+ www.nike-
10054
+ www.numberone
10055
+ www.official
10056
+ www.online
10057
+ www.onsale
10058
+ www.out
10059
+ www.penis
10060
+ www.personal
10061
+ www.promo
10062
+ www.remote
10063
+ www.replica
10064
+ www.reviewon
10065
+ www.rims
10066
+ www.sadje
10067
+ www.sale
10068
+ www.scarpe
10069
+ www.seo
10070
+ www.sexy
10071
+ www.shoes
10072
+ www.streaming
10073
+ www.tea-
10074
+ www.top
10075
+ www.torrent
10076
+ www.ugg
10077
+ www.unlock
10078
+ www.videos
10079
+ www.wholesale
10080
+ www.win
10081
+ www.wtf
10082
+ www.ysl
10083
+ www.zapato
10084
+ www<
10085
+ wwwpctool
10086
+ wypoczynku
10087
+ wyposazenie
10088
+ wywóz
10089
+ wһen
10090
+ x streaming
10091
+ x-streaming
10092
+ x.ru
10093
+ xadidas
10094
+ xalatan
10095
+ xanax
10096
+ xelerated
10097
+ xenical
10098
+ xfire.com/blog
10099
+ xl paket
10100
+ xl-paket
10101
+ xlpaket
10102
+ xn--
10103
+ xopenex
10104
+ xrumer
10105
+ xwebsite
10106
+ xx.co
10107
+ xx.in
10108
+ xxx
10109
+ xyngular
10110
+ yanswer
10111
+ yearold
10112
+ ynimb
10113
+ yo-dick
10114
+ yoigucci
10115
+ you ssay
10116
+ you-ssay
10117
+ you-ugg
10118
+ you-want-it
10119
+ you,i
10120
+ youll
10121
+ young porn
10122
+ young-porn
10123
+ your blog
10124
+ your penis
10125
+ your success
10126
+ your traffic
10127
+ your weblog
10128
+ your website
10129
+ your_
10130
+ your-account
10131
+ your-blog
10132
+ your-budget
10133
+ your-credit
10134
+ your-ex
10135
+ your-family-member
10136
+ your-free
10137
+ your-loan
10138
+ your-penis
10139
+ your-personal
10140
+ your-profile
10141
+ your-site
10142
+ your-skin
10143
+ your-success
10144
+ your-weblog
10145
+ your-website
10146
+ your-windows
10147
+ your-your
10148
+ youraccount
10149
+ yourblog
10150
+ yourcredit
10151
+ yourdui
10152
+ yourex
10153
+ yourfree
10154
+ yourloan
10155
+ yourprofile
10156
+ yoursite
10157
+ yoursuccess
10158
+ yourwebsite
10159
+ youth jersey
10160
+ youth-jersey
10161
+ youthjersey
10162
+ youtube down
10163
+ youtube vi
10164
+ youtube-down
10165
+ youtube-vi
10166
+ youtubedown
10167
+ youtubevi
10168
+ youugg
10169
+ yoyo diet
10170
+ yoyo-diet
10171
+ yoyodiet
10172
+ ysl chaussure
10173
+ ysl femme
10174
+ ysl-chaussure
10175
+ ysl-femme
10176
+ yslchaussure
10177
+ yslfemme
10178
+ yumeeyum
10179
+ yuuguu
10180
+ yyou
10181
+ ÿþ
10182
+ yеar
10183
+ z.in
10184
+ zabaw
10185
+ zahnversicherung
10186
+ zahnzusatzversicherung
10187
+ zaidimai
10188
+ zaindeksowany
10189
+ zakazane
10190
+ zaklady
10191
+ zanaflex
10192
+ zanotti online
10193
+ zanotti sale
10194
+ zanotti shoe
10195
+ zanotti sneak
10196
+ zanotti-online
10197
+ zanotti-sale
10198
+ zanotti-shoe
10199
+ zanotti-sneak
10200
+ zanottionline
10201
+ zanottisale
10202
+ zanottishoe
10203
+ zanottisneak
10204
+ zantac
10205
+ zapatas asics
10206
+ zapatas_
10207
+ zapatas-asics
10208
+ zapatillas asics
10209
+ zapatillas_
10210
+ zapatillas-asics
10211
+ zapatodenewbalance
10212
+ zapraszam
10213
+ zawieszki
10214
+ zboard.php
10215
+ zcode
10216
+ zdrowie
10217
+ zealous of
10218
+ zealous-of
10219
+ zed-bull
10220
+ zedbull
10221
+ zenonia
10222
+ zero calorie
10223
+ zero-calorie
10224
+ zerocalorie
10225
+ zfymail
10226
+ zikinell
10227
+ zimmerman fund
10228
+ zimmerman hedge
10229
+ zimmerman-fund
10230
+ zimmerman-hedge
10231
+ zimovane
10232
+ zinger baseball
10233
+ zinger bat
10234
+ zinger-baseball
10235
+ zinger-bat
10236
+ zippo feuerzeuge
10237
+ zippo zubehor
10238
+ zippo zubehör
10239
+ zippo-feuerzeuge
10240
+ zippo-zubehor
10241
+ zippo-zubehör
10242
+ zippofeuerzeuge
10243
+ zippozubehor
10244
+ zippozubehör
10245
+ zithromax
10246
+ zlinks
10247
+ złote
10248
+ zmedicin
10249
+ zoe boot
10250
+ zoe-boot
10251
+ zoidstore
10252
+ zoloft
10253
+ zolpidem
10254
+ zonejp
10255
+ zopiclone
10256
+ zovirax
10257
+ zsurgical
10258
+ zumbah
10259
+ zvideo
10260
+ zxog
10261
+ zyban
10262
+ zyprexa
10263
+ zyrtec
10264
+ zyvox
10265
+ οn
10266
+ ύou
10267
+ ωhil
10268
+ ωіlly
10269
+ аl
10270
+ аr
10271
+ абонентская
10272
+ авиабилет
10273
+ агенств
10274
+ админу
10275
+ алкогольные
10276
+ альтернатива
10277
+ андроид
10278
+ банков
10279
+ без
10280
+ бензогенератор
10281
+ бесплатн
10282
+ блог
10283
+ вђ
10284
+ веб
10285
+ г©
10286
+ денег
10287
+ дешево
10288
+ доход
10289
+ доходы
10290
+ драйвера
10291
+ заболевани
10292
+ заработок
10293
+ зарегистрировать
10294
+ знакомства
10295
+ инете
10296
+ интересн
10297
+ интернет
10298
+ іt
10299
+ казино
10300
+ качест
10301
+ качественный
10302
+ квартир
10303
+ китай
10304
+ клубах
10305
+ комисси
10306
+ компьютер
10307
+ консультация
10308
+ кредит
10309
+ купить
10310
+ легальные
10311
+ магаз
10312
+ маркет
10313
+ массажистка
10314
+ материал
10315
+ мебель
10316
+ медиа палитра
10317
+ метал
10318
+ миллион
10319
+ молочной
10320
+ найти человека
10321
+ недорого
10322
+ новинки
10323
+ обучение
10324
+ объявлени
10325
+ одежда
10326
+ онлайн
10327
+ отзывы
10328
+ отличные
10329
+ официальных
10330
+ персональный
10331
+ плата
10332
+ подешевле
10333
+ пожаловать
10334
+ покер
10335
+ порно
10336
+ портал
10337
+ посетител
10338
+ похудению
10339
+ преобрести
10340
+ прибыль
10341
+ привлекательный
10342
+ приобрести
10343
+ продаже
10344
+ проститутки
10345
+ професси
10346
+ прошивка
10347
+ психоло
10348
+ путешествую
10349
+ рднк
10350
+ регистратор
10351
+ рекламное
10352
+ ресниц
10353
+ ресурс
10354
+ рублей
10355
+ сайтов
10356
+ секс
10357
+ селитра
10358
+ симпатичная
10359
+ симптом
10360
+ скачать
10361
+ спама
10362
+ спорт на
10363
+ спорт открытом
10364
+ спорт-на
10365
+ спорт-открытом
10366
+ справкой
10367
+ статей
10368
+ статья
10369
+ стоимость
10370
+ супер
10371
+ съемка
10372
+ такси
10373
+ трудоустройства
10374
+ уou
10375
+ удивительные
10376
+ услуг
10377
+ фабрика меха
10378
+ фильмов
10379
+ финансовую
10380
+ фирму
10381
+ форум
10382
+ фото
10383
+ футбол
10384
+ цена
10385
+ шапка-
10386
+ элитныеноутбуки
10387
+ юридической
10388
+ ԝill
10389
+ ոeutral
10390
+ ոotie
10391
+ ߋ
10392
+ คาสิโน
10393
+ ต่างหู
10394
+ 루이비통
10395
+ アークテリクス
10396
+ アウトレット
10397
+ アディダス
10398
+ アメリカン エキスプレス
10399
+ アメリカン·エキスプレス
10400
+ アルマーニ
10401
+ いい
10402
+ いホスティング
10403
+ ヴィトン
10404
+ ヴェネタ
10405
+ ヴェルサーチ
10406
+ エアジョーダン
10407
+ エスパドリーユ
10408
+ エルメス
10409
+ オークリー
10410
+ おざ
10411
+ オロビアンコ
10412
+ お客
10413
+ お店を
10414
+ お金を
10415
+ ガガ
10416
+ カナダグース
10417
+ カルティエは
10418
+ ギフト
10419
+ グッチ
10420
+ クラシック
10421
+ クロエ
10422
+ クロムハーツ
10423
+ ケース
10424
+ ケイトスペード
10425
+ コピ
10426
+ ゴヤール
10427
+ ご了承
10428
+ ご返金
10429
+ サマンサタバサ
10430
+ ショッ
10431
+ ショルダーバッグ
10432
+ スニーカー
10433
+ スポード
10434
+ スワロフスキー
10435
+ セイコー
10436
+ セクシー
10437
+ セリーヌ
10438
+ ダウン
10439
+ ダコタ
10440
+ ダナー
10441
+ ダミエ
10442
+ チャンルー
10443
+ ティファニ
10444
+ ティンバ
10445
+ デュベティカ
10446
+ トゥミ
10447
+ トリーバーチ
10448
+ トレッキングシューズ
10449
+ ナイキ
10450
+ ニューバランス
10451
+ ネックレス
10452
+ ノースフェイス
10453
+ の値段
10454
+ バーバリー
10455
+ パタゴニア
10456
+ バッグ
10457
+ パネライ
10458
+ バンクオブアメリカ
10459
+ ビトン
10460
+ ブーツ
10461
+ フェラガモ
10462
+ フェンディ
10463
+ ブが広がります
10464
+ プライバシ
10465
+ ブランド
10466
+ ブルガリ
10467
+ ブレスレット
10468
+ ブログ
10469
+ プロダ
10470
+ プロモ
10471
+ ポーター
10472
+ ホグロフス
10473
+ ボッテガ
10474
+ ホット
10475
+ マークジェイコブス
10476
+ ミュウ
10477
+ ムービー用
10478
+ モンクレール
10479
+ モンブラン
10480
+ ユーチューブ
10481
+ ラウンジ
10482
+ ラゲージ
10483
+ ルイヴィトン
10484
+ ルブタン
10485
+ レシート
10486
+ レスポートサック
10487
+ レプリカ
10488
+ ロレックス
10489
+ ワンランク上の
10490
+ 万年筆
10491
+ 人気
10492
+ 仕入れ
10493
+ 他の製品
10494
+ 保存
10495
+ 保証
10496
+ 割引
10497
+ 化粧
10498
+ 医師
10499
+ 博彩
10500
+ 危機
10501
+ 取得
10502
+ 受注
10503
+ 吉田カバン
10504
+ 商品
10505
+ 外贸
10506
+ 安い
10507
+ 実店舗
10508
+ 小銭入れ
10509
+
10510
+ 巨大
10511
+ 店の
10512
+ 性愛的
10513
+ 最安値
10514
+ 札入れ
10515
+ 毛刈
10516
+ 漫画を
10517
+ 激安
10518
+ 無料に
10519
+ 用品
10520
+ 百家乐
10521
+ 直営店
10522
+ 真のメリット
10523
+ 秋冬
10524
+ 節約
10525
+ 綺麗め
10526
+ 脳症
10527
+
10528
+ 腕時計
10529
+ 興奮
10530
+ 芸能人
10531
+
10532
+ 血症
10533
+ 行動電源
10534
+ 評価
10535
+ 財布
10536
+ 貿易
10537
+ 赌场
10538
+ 輸入
10539
+ 返品
10540
+ 通信販売
10541
+ 通販
10542
+ 配送
10543
+ 酒嗜
10544
+ 金引換
10545
+ 金融
10546
+ 鈥?
10547
+
10548
+ 革の
10549
+ ?>
src/icwp-base-processor.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * Version: 2013-08-27-B
@@ -18,9 +18,9 @@
18
  *
19
  */
20
 
21
- if ( !class_exists('ICWP_BaseProcessor_WPSF') ):
22
 
23
- class ICWP_BaseProcessor_WPSF {
24
 
25
  const PcreDelimiter = '/';
26
  const LOG_MESSAGE_LEVEL_INFO = 0;
@@ -31,6 +31,11 @@ class ICWP_BaseProcessor_WPSF {
31
  const LOG_CATEGORY_FIREWALL = 1;
32
  const LOG_CATEGORY_LOGINPROTECT = 2;
33
 
 
 
 
 
 
34
  /**
35
  * @var boolean
36
  */
@@ -70,7 +75,8 @@ class ICWP_BaseProcessor_WPSF {
70
  */
71
  protected $m_oOptionsHandler;
72
 
73
- public function __construct() {
 
74
  $this->m_fNeedSave = true;
75
  $this->reset();
76
  }
@@ -79,10 +85,15 @@ class ICWP_BaseProcessor_WPSF {
79
  * Resets the object values to be re-used anew
80
  */
81
  public function reset() {
82
- $this->m_nRequestIp = self::GetVisitorIpAddress();
83
  $this->resetLog();
84
  }
85
 
 
 
 
 
 
86
  /**
87
  * Ensure that when we save the object later, it doesn't save unnecessary data.
88
  */
@@ -91,15 +102,20 @@ class ICWP_BaseProcessor_WPSF {
91
  }
92
 
93
  /**
94
- * @param string $infKey
95
  */
96
- public function store( $infKey ) {
 
97
  if ( $this->getNeedSave() ) {
98
- $this->doPreStore();
99
  $this->setNeedSave( false );
100
- update_option( $infKey, $this );
101
  }
102
  }
 
 
 
 
 
 
103
 
104
  /**
105
  * @return boolean
@@ -117,20 +133,40 @@ class ICWP_BaseProcessor_WPSF {
117
 
118
  /**
119
  *
120
- * @param array $inoOptions
121
  */
122
  public function setOptions( &$inaOptions ) {
123
  $this->m_aOptions = $inaOptions;
124
  }
125
  /**
126
  *
127
- * @param array $inoOptionsHandler
128
  */
129
  public function setOptionsHandler( ICWP_OptionsHandler_Base_WPSF &$inoOptionsHandler ) {
130
  $this->m_oOptionsHandler = $inoOptionsHandler;
131
  $this->m_aOptions = $this->m_oOptionsHandler->getPluginOptionsValues();
132
  }
133
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  /**
135
  * Resets the log
136
  */
@@ -196,49 +232,12 @@ class ICWP_BaseProcessor_WPSF {
196
  /**
197
  * Cloudflare compatible.
198
  *
199
- * @return number - visitor IP Address as IP2Long
200
- */
201
- public static function GetVisitorIpAddress( $infAsLong = true ) {
202
-
203
- $aAddressSourceOptions = array(
204
- 'HTTP_CLIENT_IP',
205
- 'HTTP_X_FORWARDED_FOR',
206
- 'HTTP_X_FORWARDED',
207
- 'HTTP_FORWARDED',
208
- 'REMOTE_ADDR'
209
- );
210
-
211
- $fCanUseFilter = function_exists( 'filter_var' ) && defined( 'FILTER_FLAG_NO_PRIV_RANGE' ) && defined( 'FILTER_FLAG_IPV4' );
212
-
213
- $aIpAddresses = array();
214
- foreach( $aAddressSourceOptions as $sOption ) {
215
- if ( empty( $_SERVER[ $sOption ] ) ) {
216
- continue;
217
- }
218
- $sIpAddressToTest = $_SERVER[ $sOption ];
219
-
220
- $aIpAddresses = explode( ',', $sIpAddressToTest ); //sometimes a comma-separated list is returned
221
- foreach( $aIpAddresses as $sIpAddress ) {
222
-
223
- if ( $fCanUseFilter && !self::IsAddressInPublicIpRange( $sIpAddress ) ) {
224
- continue;
225
- }
226
- else {
227
- return $infAsLong? ip2long( $sIpAddress ) : $sIpAddress;
228
- }
229
- }
230
- }
231
- return false;
232
- }
233
-
234
- /**
235
- * Assumes a valid IPv4 address is provided as we're only testing for a whether the IP is public or not.
236
- *
237
- * @param string $insIpAddress
238
- * @uses filter_var
239
  */
240
- public static function IsAddressInPublicIpRange( $insIpAddress ) {
241
- return filter_var( $insIpAddress, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE );
 
242
  }
243
 
244
  /**
@@ -305,7 +304,7 @@ class ICWP_BaseProcessor_WPSF {
305
  *
306
  * @param ICWP_EmailProcessor $inoEmailHandler
307
  */
308
- public function setEmailHandler( ICWP_EmailProcessor &$inoEmailHandler ) {
309
  $this->m_oEmailHandler = $inoEmailHandler;
310
  }
311
 
@@ -331,23 +330,76 @@ class ICWP_BaseProcessor_WPSF {
331
  /**
332
  * Checks the $inaData contains valid key values as laid out in $inaChecks
333
  *
334
- * @param array $inaData
335
  * @param array $inaChecks
336
  * @return boolean
337
  */
338
- protected function validateParameters( $inaData, $inaChecks ) {
339
 
340
- if ( !is_array( $inaData ) ) {
341
  return false;
342
  }
343
 
344
  foreach( $inaChecks as $sCheck ) {
345
- if ( !array_key_exists( $sCheck, $inaData ) || empty( $inaData[ $sCheck ] ) ) {
346
  return false;
347
  }
348
  }
349
  return true;
350
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  }
352
 
 
 
 
 
353
  endif;
1
  <?php
2
  /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * Version: 2013-08-27-B
18
  *
19
  */
20
 
21
+ if ( !class_exists('ICWP_BaseProcessor_V2') ):
22
 
23
+ class ICWP_BaseProcessor_V2 {
24
 
25
  const PcreDelimiter = '/';
26
  const LOG_MESSAGE_LEVEL_INFO = 0;
31
  const LOG_CATEGORY_FIREWALL = 1;
32
  const LOG_CATEGORY_LOGINPROTECT = 2;
33
 
34
+ /**
35
+ * @var string
36
+ */
37
+ protected $m_sStorageKey;
38
+
39
  /**
40
  * @var boolean
41
  */
75
  */
76
  protected $m_oOptionsHandler;
77
 
78
+ public function __construct( $insStorageKey ) {
79
+ $this->m_sStorageKey = $insStorageKey;
80
  $this->m_fNeedSave = true;
81
  $this->reset();
82
  }
85
  * Resets the object values to be re-used anew
86
  */
87
  public function reset() {
88
+ $this->m_nRequestIp = $this->getVisitorIpAddress();
89
  $this->resetLog();
90
  }
91
 
92
+ /**
93
+ * Override to set what this processor does when it's "run"
94
+ */
95
+ public function run() { }
96
+
97
  /**
98
  * Ensure that when we save the object later, it doesn't save unnecessary data.
99
  */
102
  }
103
 
104
  /**
 
105
  */
106
+ public function store() {
107
+ $this->doPreStore();
108
  if ( $this->getNeedSave() ) {
 
109
  $this->setNeedSave( false );
110
+ update_option( $this->m_sStorageKey, $this );
111
  }
112
  }
113
+
114
+ /**
115
+ */
116
+ public function deleteStore() {
117
+ delete_option( $this->m_sStorageKey );
118
+ }
119
 
120
  /**
121
  * @return boolean
133
 
134
  /**
135
  *
136
+ * @param array $inaOptions
137
  */
138
  public function setOptions( &$inaOptions ) {
139
  $this->m_aOptions = $inaOptions;
140
  }
141
  /**
142
  *
143
+ * @param ICWP_OptionsHandler_Base_WPSF $inoOptionsHandler
144
  */
145
  public function setOptionsHandler( ICWP_OptionsHandler_Base_WPSF &$inoOptionsHandler ) {
146
  $this->m_oOptionsHandler = $inoOptionsHandler;
147
  $this->m_aOptions = $this->m_oOptionsHandler->getPluginOptionsValues();
148
  }
149
+
150
+ /**
151
+ * @param $insKey
152
+ * @param bool $inmDefault
153
+ * @return bool
154
+ */
155
+ public function getOption( $insKey, $inmDefault = false ) {
156
+ return isset( $this->m_aOptions[$insKey] )? $this->m_aOptions[$insKey] : $inmDefault;
157
+ }
158
+
159
+ /**
160
+ * @param $sKey
161
+ * @param mixed $mValueToTest
162
+ * @param boolean $fStrict
163
+ * @return bool
164
+ */
165
+ public function getIsOption( $sKey, $mValueToTest, $fStrict = false ) {
166
+ $mOptionValue = $this->getOption($sKey);
167
+ return $fStrict? $mOptionValue === $mValueToTest : $mOptionValue == $mValueToTest;
168
+ }
169
+
170
  /**
171
  * Resets the log
172
  */
232
  /**
233
  * Cloudflare compatible.
234
  *
235
+ * @param boolean $infAsLong - visitor IP Address as IP2Long
236
+ * @return integer - visitor IP Address as IP2Long
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  */
238
+ public function getVisitorIpAddress( $infAsLong = true ) {
239
+ require_once( dirname(__FILE__).'/icwp-data-processor.php' );
240
+ return ICWP_WPSF_DataProcessor::GetVisitorIpAddress( $infAsLong );
241
  }
242
 
243
  /**
304
  *
305
  * @param ICWP_EmailProcessor $inoEmailHandler
306
  */
307
+ public function setEmailHandler( &$inoEmailHandler ) {
308
  $this->m_oEmailHandler = $inoEmailHandler;
309
  }
310
 
330
  /**
331
  * Checks the $inaData contains valid key values as laid out in $inaChecks
332
  *
333
+ * @param array $aData
334
  * @param array $inaChecks
335
  * @return boolean
336
  */
337
+ protected function validateParameters( $aData, $inaChecks ) {
338
 
339
+ if ( !is_array( $aData ) ) {
340
  return false;
341
  }
342
 
343
  foreach( $inaChecks as $sCheck ) {
344
+ if ( !array_key_exists( $sCheck, $aData ) || empty( $aData[ $sCheck ] ) ) {
345
  return false;
346
  }
347
  }
348
  return true;
349
  }
350
+
351
+ protected function constructStorageKey( $insPrefix = '', $insSlug = '' ) {
352
+ $sTemplate = '%s%s_processor';
353
+ return sprintf($sTemplate, $insPrefix, $insSlug );
354
+ }
355
+
356
+ /**
357
+ * Override this to provide custom cleanup.
358
+ */
359
+ public function deleteAndCleanUp() {
360
+ $this->deleteStore();
361
+ }
362
+
363
+ /**
364
+ */
365
+ protected function loadDataProcessor() {
366
+ require_once( dirname(__FILE__) . '/icwp-data-processor.php' );
367
+ }
368
+
369
+ /**
370
+ * @return ICWP_WpFilesystem_WPSF
371
+ */
372
+ protected function loadFileSystemProcessor() {
373
+ require_once( dirname(__FILE__) . '/icwp-wpfilesystem.php' );
374
+ return ICWP_WpFilesystem_WPSF::GetInstance();
375
+ }
376
+
377
+ /**
378
+ * @return ICWP_WpFunctions_WPSF
379
+ */
380
+ protected function loadWpFunctionsProcessor() {
381
+ require_once( dirname(__FILE__) . '/icwp-wpfunctions.php' );
382
+ return ICWP_WpFunctions_WPSF::GetInstance();
383
+ }
384
+
385
+ /**
386
+ * @return ICWP_WpFunctions_WPSF
387
+ */
388
+ protected function loadWpsfStatsProcessor() {
389
+ require_once( dirname(__FILE__) . '/icwp-wpsf-stats.php' );
390
+ }
391
+
392
+ /**
393
+ * @param $sStatKey
394
+ */
395
+ protected function doStatIncrement( $sStatKey ) {
396
+ $this->loadWpsfStatsProcessor();
397
+ ICWP_Stats_WPSF::DoStatIncrement( $sStatKey );
398
+ }
399
  }
400
 
401
+ endif;
402
+
403
+ if ( !class_exists('ICWP_WPSF_BaseProcessor') ):
404
+ class ICWP_WPSF_BaseProcessor extends ICWP_BaseProcessor_V2 { }
405
  endif;
src/icwp-basedb-processor.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -20,9 +20,13 @@ require_once( dirname(__FILE__).'/icwp-base-processor.php' );
20
 
21
  if ( !class_exists('ICWP_BaseDbProcessor_WPSF') ):
22
 
23
- class ICWP_BaseDbProcessor_WPSF extends ICWP_BaseProcessor_WPSF {
24
 
25
  const DB_TABLE_PREFIX = 'icwp_';
 
 
 
 
26
 
27
  /**
28
  * A link to the WordPress Database object so we don't have to "global" that every time.
@@ -35,11 +39,16 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_BaseProcessor_WPSF {
35
  * @var string
36
  */
37
  protected $m_sTableName;
 
 
 
 
38
 
39
- public function __construct( $insTableName ) {
40
- parent::__construct();
41
  $this->reset();
42
  $this->setTableName( $insTableName );
 
43
  }
44
 
45
  /**
@@ -47,6 +56,7 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_BaseProcessor_WPSF {
47
  */
48
  public function doPreStore() {
49
  parent::doPreStore();
 
50
  unset( $this->m_oWpdb );
51
  }
52
 
@@ -55,10 +65,82 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_BaseProcessor_WPSF {
55
  */
56
  public function reset() {
57
  parent::reset();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  global $wpdb;
59
  $this->m_oWpdb = $wpdb;
60
  }
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  public function insertIntoTable( $inaData ) {
63
  return $this->m_oWpdb->insert( $this->m_sTableName, $inaData );
64
  }
@@ -83,6 +165,19 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_BaseProcessor_WPSF {
83
  public function deleteRowsFromTable( $inaWhere ) {
84
  return $this->m_oWpdb->delete( $this->m_sTableName, $inaWhere );
85
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  public function createTable() {
88
  //Override this function to create the Table you want.
@@ -118,13 +213,48 @@ class ICWP_BaseDbProcessor_WPSF extends ICWP_BaseProcessor_WPSF {
118
  * @param string $insSql
119
  */
120
  public function doSql( $insSql ) {
121
- return $this->m_oWpdb->query( $insSql );
 
 
122
  }
123
 
124
  private function setTableName( $insTableName ) {
125
- return $this->m_sTableName = $this->m_oWpdb->base_prefix . self::DB_TABLE_PREFIX . $insTableName;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  }
129
 
130
  endif;
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
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
  /**
32
  * A link to the WordPress Database object so we don't have to "global" that every time.
39
  * @var string
40
  */
41
  protected $m_sTableName;
42
+ /**
43
+ * @var array
44
+ */
45
+ protected $m_aDataToWrite;
46
 
47
+ public function __construct( $insStorageKey, $insTableName ) {
48
+ parent::__construct( $insStorageKey );
49
  $this->reset();
50
  $this->setTableName( $insTableName );
51
+ $this->createCleanupCron();
52
  }
53
 
54
  /**
56
  */
57
  public function doPreStore() {
58
  parent::doPreStore();
59
+ $this->commitData();
60
  unset( $this->m_oWpdb );
61
  }
62
 
65
  */
66
  public function reset() {
67
  parent::reset();
68
+ $this->loadWpdb();
69
+ }
70
+
71
+ /**
72
+ * Override to set what this processor does when it's "run"
73
+ */
74
+ public function run() {
75
+ if ( $this->getTableExists() ) {
76
+ add_action( self::CleanupCronActionHook, array( $this, 'cleanupDatabase' ) );
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Loads our WPDB object if required.
82
+ */
83
+ protected function loadWpdb() {
84
+ if ( !is_null( $this->m_oWpdb ) ) {
85
+ return;
86
+ }
87
  global $wpdb;
88
  $this->m_oWpdb = $wpdb;
89
  }
90
 
91
+ /**
92
+ * @param array $inaLogData
93
+ * @return type
94
+ */
95
+ public function addDataToWrite( $inaLogData ) {
96
+ if ( empty( $inaLogData ) || empty( $inaLogData['messages'] ) ) {
97
+ return;
98
+ }
99
+ if ( empty( $this->m_aDataToWrite ) ) {
100
+ $this->m_aDataToWrite = array();
101
+ }
102
+ $this->m_aDataToWrite[] = $this->completeDataForWrite( $inaLogData );
103
+ }
104
+
105
+ /**
106
+ * Ensures the data provided for writing to the db meets all the requirements.
107
+ *
108
+ * This should be overridden per implementation
109
+ *
110
+ * @return array
111
+ */
112
+ protected function completeDataForWrite( $inaLogData ) {
113
+ if ( is_null( $inaLogData ) ) {
114
+ return array();
115
+ }
116
+ return $inaLogData;
117
+ }
118
+
119
+ /**
120
+ * @return boolean - whether the write to the DB was successful.
121
+ */
122
+ public function commitData() {
123
+ if ( empty( $this->m_aDataToWrite ) ) {
124
+ return;
125
+ }
126
+ $this->loadWpdb();
127
+ $fSuccess = true;
128
+ foreach( $this->m_aDataToWrite as $aDataEntry ) {
129
+ $fSuccess = $fSuccess && $this->insertIntoTable( $aDataEntry );
130
+ }
131
+ if ( $fSuccess ) {
132
+ $this->flushData();
133
+ }
134
+ return $fSuccess;
135
+ }
136
+
137
+ /**
138
+ *
139
+ */
140
+ protected function flushData() {
141
+ $this->m_aDataToWrite = null;
142
+ }
143
+
144
  public function insertIntoTable( $inaData ) {
145
  return $this->m_oWpdb->insert( $this->m_sTableName, $inaData );
146
  }
165
  public function deleteRowsFromTable( $inaWhere ) {
166
  return $this->m_oWpdb->delete( $this->m_sTableName, $inaWhere );
167
  }
168
+
169
+ protected function deleteAllRowsOlderThan( $innTimeStamp ) {
170
+ $sQuery = "
171
+ DELETE from `%s`
172
+ WHERE
173
+ `created_at` < '%s'
174
+ ";
175
+ $sQuery = sprintf( $sQuery,
176
+ $this->m_sTableName,
177
+ $innTimeStamp
178
+ );
179
+ $this->doSql( $sQuery );
180
+ }
181
 
182
  public function createTable() {
183
  //Override this function to create the Table you want.
213
  * @param string $insSql
214
  */
215
  public function doSql( $insSql ) {
216
+ $this->loadWpdb();
217
+ $fResult = $this->m_oWpdb->query( $insSql );
218
+ return $fResult;
219
  }
220
 
221
  private function setTableName( $insTableName ) {
222
+ return $this->m_sTableName = esc_sql( $this->m_oWpdb->base_prefix . self::DB_TABLE_PREFIX . $insTableName );
223
+ }
224
+
225
+ /**
226
+ * Override this to provide custom cleanup.
227
+ */
228
+ public function deleteAndCleanUp() {
229
+ parent::deleteAndCleanUp();
230
+ $this->dropTable();
231
+ }
232
+
233
+ /**
234
+ * Will setup the cleanup cron to clean out old entries. This should be overridden per implementation.
235
+ */
236
+ protected function createCleanupCron() {
237
+ if ( ! wp_next_scheduled( self::CleanupCronActionHook ) && ! defined( 'WP_INSTALLING' ) ) {
238
+ $nNextRun = strtotime( 'tomorrow 6am' ) - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
239
+ wp_schedule_event( $nNextRun, 'daily', self::CleanupCronActionHook );
240
+ }
241
  }
242
 
243
+ public function cleanupDatabase() {
244
+ //by default do nothing - oiverrde this method
245
+ }
246
+
247
+ /**
248
+ * @return bool
249
+ */
250
+ public function getTableExists() {
251
+ $sQuery = "
252
+ SHOW TABLES LIKE '%s'
253
+ ";
254
+ $sQuery = sprintf( $sQuery, $this->m_sTableName );
255
+ $mResult = $this->m_oWpdb->get_var( $sQuery );
256
+ return !is_null( $mResult );
257
+ }
258
  }
259
 
260
  endif;
src/icwp-data-processor.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
5
  * All rights reserved.
6
  *
7
  * Version: 2013-08-27-A
@@ -19,12 +19,62 @@
19
  *
20
  */
21
 
22
- if ( !class_exists('ICWP_DataProcessor') ):
23
 
24
- class ICWP_DataProcessor {
25
 
26
  public static $fUseFilter = false;
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  static public function ExtractIpAddresses( $insAddresses = '' ) {
29
 
30
  $aRawAddresses = array();
@@ -96,11 +146,13 @@ class ICWP_DataProcessor {
96
  *
97
  * @param array $inaCurrent - the list to which to add the new addresses
98
  * @param array $inaNewRawAddresses - the new IPv4 addresses
99
- * @param int $outnNewAdded - the count of newly added IPs
100
  * @return unknown|Ambigous <multitype:multitype: , string>
101
  */
102
  public static function Add_New_Raw_Ips( $inaCurrent, $inaNewRawAddresses, &$outnNewAdded = 0 ) {
103
 
 
 
104
  if ( empty( $inaNewRawAddresses ) ) {
105
  return $inaCurrent;
106
  }
@@ -200,6 +252,65 @@ class ICWP_DataProcessor {
200
  }
201
  return false;
202
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
  /**
205
  * The only ranges currently accepted are a.b.c.d-f.g.h.j
@@ -231,6 +342,24 @@ class ICWP_DataProcessor {
231
  return false;
232
  }
233
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  /**
235
  * @param integer $innLength
236
  * @param boolean $infBeginLetter
@@ -254,6 +383,71 @@ class ICWP_DataProcessor {
254
  }
255
  return $sPassword;
256
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  }
258
 
 
 
 
 
259
  endif;
1
  <?php
2
 
3
  /**
4
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
5
  * All rights reserved.
6
  *
7
  * Version: 2013-08-27-A
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
+ * Cloudflare compatible.
30
+ *
31
+ * @param boolean $infAsLong
32
+ * @return bool|integer - visitor IP Address as IP2Long
33
+ */
34
+ public static function GetVisitorIpAddress( $infAsLong = true ) {
35
+
36
+ $aAddressSourceOptions = array(
37
+ 'HTTP_CF_CONNECTING_IP',
38
+ 'HTTP_CLIENT_IP',
39
+ 'HTTP_X_FORWARDED_FOR',
40
+ 'HTTP_X_FORWARDED',
41
+ 'HTTP_FORWARDED',
42
+ 'REMOTE_ADDR'
43
+ );
44
+ $fCanUseFilter = function_exists( 'filter_var' ) && defined( 'FILTER_FLAG_NO_PRIV_RANGE' ) && defined( 'FILTER_FLAG_IPV4' );
45
+
46
+ $aIpAddresses = array();
47
+ foreach( $aAddressSourceOptions as $sOption ) {
48
+ if ( empty( $_SERVER[ $sOption ] ) ) {
49
+ continue;
50
+ }
51
+ $sIpAddressToTest = $_SERVER[ $sOption ];
52
+
53
+ $aIpAddresses = explode( ',', $sIpAddressToTest ); //sometimes a comma-separated list is returned
54
+ foreach( $aIpAddresses as $sIpAddress ) {
55
+
56
+ if ( $fCanUseFilter && !self::IsAddressInPublicIpRange( $sIpAddress ) ) {
57
+ continue;
58
+ }
59
+ else {
60
+ return $infAsLong? ip2long( $sIpAddress ) : $sIpAddress;
61
+ }
62
+ }
63
+ }
64
+ return false;
65
+ }
66
+
67
+ /**
68
+ * Assumes a valid IPv4 address is provided as we're only testing for a whether the IP is public or not.
69
+ *
70
+ * @param string $insIpAddress
71
+ * @uses filter_var
72
+ * @return boolean
73
+ */
74
+ public static function IsAddressInPublicIpRange( $insIpAddress ) {
75
+ return filter_var( $insIpAddress, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE );
76
+ }
77
+
78
  static public function ExtractIpAddresses( $insAddresses = '' ) {
79
 
80
  $aRawAddresses = array();
146
  *
147
  * @param array $inaCurrent - the list to which to add the new addresses
148
  * @param array $inaNewRawAddresses - the new IPv4 addresses
149
+ * @param int $outnNewAdded - the count of newly added IPs
150
  * @return unknown|Ambigous <multitype:multitype: , string>
151
  */
152
  public static function Add_New_Raw_Ips( $inaCurrent, $inaNewRawAddresses, &$outnNewAdded = 0 ) {
153
 
154
+ $outnNewAdded = 0;
155
+
156
  if ( empty( $inaNewRawAddresses ) ) {
157
  return $inaCurrent;
158
  }
252
  }
253
  return false;
254
  }
255
+
256
+ /**
257
+ * Taken from http://www.phacks.net/detecting-search-engine-bot-and-web-spiders/
258
+ */
259
+ public static function IsSearchEngineBot() {
260
+
261
+ if ( empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
262
+ return false;
263
+ }
264
+ $sUserAgent = $_SERVER['HTTP_USER_AGENT'];
265
+ $sBots = 'Googlebot|bingbot|Twitterbot|Baiduspider|ia_archiver|R6_FeedFetcher|NetcraftSurveyAgent'
266
+ .'|Sogou web spider|Yahoo! Slurp|facebookexternalhit|PrintfulBot|msnbot|UnwindFetchor|urlresolver|Butterfly|TweetmemeBot';
267
+
268
+ return ( preg_match( "/$sBots/", $sUserAgent ) > 0 );
269
+ //
270
+ // $aBots = array(
271
+ // 'Googlebot',
272
+ // 'bingbot',
273
+ // 'Twitterbot',
274
+ // 'Baiduspider',
275
+ // 'ia_archiver',
276
+ // 'R6_FeedFetcher',
277
+ // 'NetcraftSurveyAgent',
278
+ // 'Sogou web spider',
279
+ // 'Yahoo! Slurp',
280
+ // 'facebookexternalhit',
281
+ // 'PrintfulBot',
282
+ // 'msnbot',
283
+ // 'UnwindFetchor',
284
+ // 'urlresolver',
285
+ // 'Butterfly',
286
+ // 'TweetmemeBot'
287
+ // );
288
+ //
289
+ // $aCrawlers = array(
290
+ // 'Google' => 'Google',
291
+ // 'msnbot' => 'MSN',
292
+ // 'Rambler' => 'Rambler',
293
+ // 'Yahoo' => 'Yahoo',
294
+ // 'AbachoBOT' => 'AbachoBOT',
295
+ // 'accoona' => 'Accoona',
296
+ // 'AcoiRobot' => 'AcoiRobot',
297
+ // 'ASPSeek' => 'ASPSeek',
298
+ // 'CrocCrawler' => 'CrocCrawler',
299
+ // 'Dumbot' => 'Dumbot',
300
+ // 'FAST-WebCrawler' => 'FAST-WebCrawler',
301
+ // 'GeonaBot' => 'GeonaBot',
302
+ // 'Gigabot' => 'Gigabot',
303
+ // 'Lycos' => 'Lycos spider',
304
+ // 'MSRBOT' => 'MSRBOT',
305
+ // 'Scooter' => 'Altavista robot',
306
+ // 'AltaVista' => 'Altavista robot',
307
+ // 'IDBot' => 'ID-Search Bot',
308
+ // 'eStyle' => 'eStyle Bot',
309
+ // 'Scrubby' => 'Scrubby robot'
310
+ // );
311
+
312
+ return array_key_exists( $sUserAgent, $aCrawlers );
313
+ }
314
 
315
  /**
316
  * The only ranges currently accepted are a.b.c.d-f.g.h.j
342
  return false;
343
  }
344
 
345
+ public static function CleanYubikeyUniqueKeys( $insRawKeys ) {
346
+ $aKeys = explode( "\n", $insRawKeys );
347
+ foreach( $aKeys as $nIndex => $sUsernameKey ) {
348
+ if ( empty( $sUsernameKey ) ) {
349
+ unset( $aKeys[$nIndex] );
350
+ continue;
351
+ }
352
+ $aParts = array_map( 'trim', explode( ',', $sUsernameKey ) );
353
+ if ( empty( $aParts[0] ) || empty( $aParts[1] ) || strlen( $aParts[1] ) < 12 ) {
354
+ unset( $aKeys[$nIndex] );
355
+ continue;
356
+ }
357
+ $aParts[1] = substr( $aParts[1], 0, 12 );
358
+ $aKeys[$nIndex] = array( $aParts[0] => $aParts[1] );
359
+ }
360
+ return $aKeys;
361
+ }
362
+
363
  /**
364
  * @param integer $innLength
365
  * @param boolean $infBeginLetter
383
  }
384
  return $sPassword;
385
  }
386
+
387
+ /**
388
+ * @param string $insKey
389
+ * @param boolean $infIncludeCookie
390
+ * @return mixed|null
391
+ */
392
+ public static function FetchRequest( $insKey, $infIncludeCookie = true ) {
393
+ $mFetchVal = self::FetchPost( $insKey );
394
+ if ( is_null( $mFetchVal ) ) {
395
+ $mFetchVal = self::FetchGet( $insKey );
396
+ if ( is_null( $mFetchVal && $infIncludeCookie ) ) {
397
+ $mFetchVal = self::FetchCookie( $insKey );
398
+ }
399
+ }
400
+ return $mFetchVal;
401
+ }
402
+ /**
403
+ * @param string $insKey
404
+ * @return mixed|null
405
+ */
406
+ public static function FetchGet( $insKey ) {
407
+ if ( function_exists( 'filter_input' ) && defined( 'INPUT_GET' ) ) {
408
+ return filter_input( INPUT_GET, $insKey );
409
+ }
410
+ return self::ArrayFetch( $_GET, $insKey );
411
+ }
412
+ /**
413
+ * @param string $insKey The $_POST key
414
+ * @return mixed|null
415
+ */
416
+ public static function FetchPost( $insKey ) {
417
+ if ( function_exists( 'filter_input' ) && defined( 'INPUT_POST' ) ) {
418
+ return filter_input( INPUT_POST, $insKey );
419
+ }
420
+ return self::ArrayFetch( $_POST, $insKey );
421
+ }
422
+ /**
423
+ * @param string $insKey The $_POST key
424
+ * @return mixed|null
425
+ */
426
+ public static function FetchCookie( $insKey ) {
427
+ if ( function_exists( 'filter_input' ) && defined( 'INPUT_COOKIE' ) ) {
428
+ return filter_input( INPUT_COOKIE, $insKey );
429
+ }
430
+ return self::ArrayFetch( $_COOKIE, $insKey );
431
+ }
432
+
433
+ /**
434
+ * @param array $inaArray
435
+ * @param string $insKey The array key
436
+ * @return mixed|null
437
+ */
438
+ public static function ArrayFetch( &$inaArray, $insKey ) {
439
+ if ( empty( $inaArray ) ) {
440
+ return null;
441
+ }
442
+ if ( !isset( $inaArray[$insKey] ) ) {
443
+ return null;
444
+ }
445
+ return $inaArray[$insKey];
446
+ }
447
  }
448
 
449
+ endif;
450
+
451
+ if ( !class_exists('ICWP_WPSF_DataProcessor') ):
452
+ class ICWP_WPSF_DataProcessor extends ICWP_DataProcessor_V1 { }
453
  endif;
src/icwp-feature-master.php ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * This is
7
+ * distributed under the GNU General Public License, Version 2,
8
+ * June 1991. Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin
9
+ * St, Fifth Floor, Boston, MA 02110, USA
10
+ *
11
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
12
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
13
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
15
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
17
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
18
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
20
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21
+ */
22
+
23
+ require_once( dirname(__FILE__).'/icwp-pure-base.php' );
24
+
25
+ if ( !class_exists('ICWP_Feature_Master') ):
26
+
27
+ class ICWP_Feature_Master extends ICWP_Pure_Base_V4 {
28
+
29
+ /**
30
+ *@var array
31
+ */
32
+ protected $m_aFeatures;
33
+
34
+ /**
35
+ *@var array
36
+ */
37
+ protected $m_aOptionsHandlers;
38
+
39
+ /**
40
+ * @var ICWP_OptionsHandler_Wpsf
41
+ */
42
+ protected $m_oPluginMainOptions;
43
+
44
+ protected $fHasFtpOverride = false;
45
+
46
+ public function __construct( $inaFeatures, $inaOptions ) {
47
+ parent::__construct();
48
+ $this->m_aFeatures = $inaFeatures;
49
+ $this->m_aOptionsHandlers = $inaOptions;
50
+ }
51
+
52
+ /**
53
+ * Based on the existence of files placed within the plugin directory, will enable or disable
54
+ * all registered features and return the value of the override setting that was put in place.
55
+ *
56
+ * @return string - override settings (empty string if none).
57
+ */
58
+ protected function override() {
59
+
60
+ if ( $this->m_oWpFs->exists( path_join($this->m_sPluginDir, 'forceOff') ) ) {
61
+ $fHasFtpOverride = true;
62
+ $sSetting = 'N';
63
+ }
64
+ else if ( $this->m_oWpFs->exists( path_join($this->m_sPluginDir, 'forceOn') ) ) {
65
+ $fHasFtpOverride = true;
66
+ $sSetting = 'Y';
67
+ }
68
+ else {
69
+ $sSetting = '';
70
+ }
71
+
72
+ if ( $sSetting == '' ) {
73
+ return $sSetting;
74
+ }
75
+
76
+ $aFeatures = $this->getFeaturesMap();
77
+ foreach( $aFeatures as $sFeature => $sName ) {
78
+ $this->setSharedOption( 'enable_'.$sFeature, $sSetting );
79
+ }
80
+ return $sSetting;
81
+ }
82
+
83
+ /**
84
+ * @return array
85
+ */
86
+ protected function getFeaturesMap() {
87
+ return $this->m_aFeatures;
88
+ }
89
+
90
+ /**
91
+ * Given a certain feature 'slug' will return true if this is a particular supported feature of this plugin.
92
+ *
93
+ * @param string $insFeature
94
+ * @return boolean
95
+ */
96
+ public function getIsFeature( $insFeature ) {
97
+ return array_key_exists( $insFeature, $this->getFeaturesMap() ) || in_array( $insFeature, $this->getFeaturesMap() );
98
+ }
99
+
100
+ /**
101
+ * @param string $insFeature - firewall, login_protect, comments_filter, lockdown
102
+ * @return boolean
103
+ */
104
+ public function getIsMainFeatureEnabled( $insFeature ) {
105
+
106
+ if ( $this->m_oWpFs->exists( $this->m_sPluginPath . 'forceOff' ) ) {
107
+ return false;
108
+ }
109
+ else if ( $this->m_oWpFs->exists( $this->m_sPluginPath . 'forceOn' ) ) {
110
+ return true;
111
+ }
112
+
113
+ $aFeatures = $this->getFeaturesMap();
114
+ if ( array_key_exists( $insFeature, $aFeatures ) ) {
115
+ $fEnabled = $this->m_oPluginMainOptions->getOpt( 'enable_'.$insFeature ) == 'Y';
116
+ }
117
+ else {
118
+ $fEnabled = false;
119
+ }
120
+ return $fEnabled;
121
+ }
122
+
123
+ /**
124
+ * This is necessary because we store these values in several places and we need to always keep it in sync.
125
+ *
126
+ * @param string $insOption
127
+ * @param mixed $inmValue
128
+ * @return boolean
129
+ */
130
+ public function setSharedOption( $insOption, $inmValue ) {
131
+
132
+ $aFeatures = $this->getFeaturesMap();
133
+
134
+ $sFeature = str_replace( 'enable_', '', $insOption );
135
+ if ( !array_key_exists( $sFeature, $aFeatures ) ) {
136
+ return;
137
+ }
138
+
139
+ $this->loadOptionsHandler( $aFeatures[$sFeature] );
140
+ $sOptions = 'm_o'.$aFeatures[$sFeature].'Options';// e.g. m_oFirewallOptions
141
+ $this->{$sOptions}->setOpt( $insOption, $inmValue );
142
+ $this->m_oPluginMainOptions->setOpt( $insOption, $inmValue );
143
+ }
144
+
145
+ protected function loadOptionsHandler( $insOptionHandler = 'PluginMain', $infRecreate = false, $infFullBuild = false ) {
146
+
147
+ $aAllHandlers = array_values( $this->getFeaturesMap() );
148
+ $aAllHandlers[] = 'PluginMain';
149
+
150
+ // special case
151
+ if ( $insOptionHandler == 'all' ) {
152
+ foreach( $aAllHandlers as $sHandler ) {
153
+ $fSuccess = $this->loadOptionsHandler( $sHandler, $infRecreate, $infFullBuild );
154
+ }
155
+ return $fSuccess;
156
+ }
157
+
158
+ if ( !in_array( $insOptionHandler, $aAllHandlers ) ) {
159
+ return false;
160
+ }
161
+
162
+ $sOptionsVarName = 'm_o'.$insOptionHandler.'Options'; // e.g. m_oPluginMainOptions
163
+ if ( $insOptionHandler == 'PluginMain' ) {
164
+ $sSourceFile = dirname(__FILE__).'/icwp-optionshandler-'.$this->m_sPluginSlug.'.php'; // e.g. icwp-optionshandler-wpsf.php
165
+ $sClassName = 'ICWP_OptionsHandler_'.ucfirst( $this->m_sPluginSlug ); // e.g. ICWP_OptionsHandler_Wpsf
166
+ }
167
+ else {
168
+ $sSourceFile = dirname(__FILE__).'/icwp-optionshandler-'.strtolower($insOptionHandler).'.php'; // e.g. icwp-optionshandler-wpsf.php
169
+ $sClassName = 'ICWP_OptionsHandler_'.$insOptionHandler; // e.g. ICWP_OptionsHandler_Wpsf
170
+ }
171
+
172
+ require_once( $sSourceFile );
173
+ if ( $infRecreate || !isset( $this->{$sOptionsVarName} ) ) {
174
+ $this->{$sOptionsVarName} = new $sClassName( self::$sOptionPrefix, $this->m_sVersion, $infFullBuild );
175
+ }
176
+ if ( $infFullBuild ) {
177
+ $this->{$sOptionsVarName}->buildOptions();
178
+ }
179
+ return true;
180
+ }
181
+
182
+ /**
183
+ * Given a feature/processor name will load the variable for it, including the appropriate source file.
184
+ *
185
+ * @param string $insProcessorName
186
+ * @param boolean $infRebuild
187
+ * @return ICWP_OptionsHandler_Base_Wpsf
188
+ */
189
+ protected function loadProcessor( $insProcessorName, $infRebuild = false ) {
190
+ $aAllProcessors = $this->getFeaturesMap();
191
+
192
+ if ( !in_array( $insProcessorName, array_values($aAllProcessors) ) ) {
193
+ $this->doWpDie( sprintf('Processor %s is not permitted here.', $insProcessorName) );
194
+ }
195
+ $sProcessorVarName = 'm_o'.$insProcessorName.'Processor'; // e.g. m_oFirewallProcessor
196
+ $sSourceFile = dirname(__FILE__).'/icwp-processor-'.strtolower($insProcessorName).'.php'; // e.g. icwp-optionshandler-wpsf.php
197
+ $sClassName = 'ICWP_'.strtoupper( $this->m_sPluginSlug ).'_'.$insProcessorName.'Processor'; // e.g. ICWP_WPSF_FirewallProcessor
198
+ $sStorageKey = array_search($insProcessorName, $aAllProcessors).'_processor'; // e.g. firewall_processor
199
+ $sOptionsHandlerVarName = 'm_o'.$insProcessorName.'Options'; // e.g. m_oFirewallOptions
200
+
201
+ require_once( $sSourceFile );
202
+ if ( $infRebuild || empty( $this->{$sProcessorVarName} ) ) {
203
+ $oTemp = $this->getOption( $sStorageKey );
204
+ if ( !$infRebuild && is_object( $oTemp ) && ( $oTemp instanceof $sClassName ) ) {
205
+ $oTemp->reset();
206
+ }
207
+ else {
208
+ $oTemp = new $sClassName( self::$sOptionPrefix );
209
+ }
210
+ $this->{$sProcessorVarName} = $oTemp;
211
+ }
212
+ if ( $this->loadOptionsHandler( $insProcessorName ) ) {
213
+ $aOptionsValues = $this->{$sOptionsHandlerVarName}->getPluginOptionsValues();
214
+ $this->{$sProcessorVarName}->setOptions( $aOptionsValues );
215
+ }
216
+ return $this->{$sProcessorVarName};
217
+ }
218
+
219
+ protected function resetProcessor( $insProcessorName ) {
220
+ if ( !$this->getIsFeature( $insProcessorName ) ) {
221
+ $this->doWpDie('Not a processor: '.$insProcessorName);
222
+ return;
223
+ }
224
+ $this->loadProcessor( $insProcessorName );
225
+ return;
226
+ }
227
+
228
+ protected function resetOptionHandler( $insOptionName ) {
229
+ if ( !$this->getIsFeature( $insOptionName ) ) {
230
+ $this->doWpDie('Not a feature: '.$insOptionName);
231
+ return;
232
+ }
233
+ $this->loadOptionsHandler( $insOptionName );
234
+ return;
235
+ }
236
+
237
+ public function clearCaches() {
238
+ $aFeatures = $this->getFeaturesMap();
239
+ foreach( $aFeatures as $sFeature ) {
240
+ $this->resetOptionHandler( $sFeature );
241
+ $this->resetProcessor( $sFeature );
242
+ }
243
+ }
244
+
245
+ protected function getAllOptionsHandlers() {
246
+ $this->loadOptionsHandler('all');
247
+ $aOptions = array();
248
+ foreach( $this->m_aOptionsHandlers as $sName ) {
249
+ if ( isset( $this->{$sName} ) ) {
250
+ $aOptions[] = &$this->{$sName};
251
+ }
252
+ }
253
+ return $aOptions;
254
+ }
255
+
256
+ /**
257
+ * Makes sure and cache the processors after all is said and done.
258
+ */
259
+ public function saveProcessors() {
260
+ $aFeatures = $this->getFeaturesMap();
261
+ foreach( $aFeatures as $sSlug => $sProcessorName ) {
262
+ $oProcessor = $this->getProcessorVar( $sProcessorName );
263
+ if ( !is_null($oProcessor) && is_object($oProcessor) ) {
264
+ $oProcessor->store();
265
+ }
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Makes sure and cache the processors after all is said and done.
271
+ */
272
+ public function saveOptions() {
273
+ $aOptions = $this->getAllOptionsHandlers();
274
+ foreach( $aOptions as &$oOption ) {
275
+ if ( isset( $oOption ) ) {
276
+ $oOption->savePluginOptions();
277
+ }
278
+ }
279
+ }
280
+
281
+ /**
282
+ *
283
+ * @param string $insProcessorName
284
+ * @param bool $infLoad
285
+ * @return null|ICWP_WPSF_BaseProcessor
286
+ */
287
+ protected function getProcessorVar( $insProcessorName, $infLoad = false ) {
288
+ if ( !$this->getIsFeature( $insProcessorName ) ) {
289
+ return null;
290
+ }
291
+ $sProcessorVariable = 'm_o'.$insProcessorName.'Processor';
292
+ if ( $infLoad || !isset( $this->{$sProcessorVariable} ) ) {
293
+ $this->loadProcessor( $insProcessorName );
294
+ }
295
+ $sProcessorVariable = 'm_o'.$insProcessorName.'Processor';
296
+ return $this->{$sProcessorVariable};
297
+ }
298
+
299
+ protected function shutdown() {
300
+ parent::shutdown();
301
+ $this->saveOptions();
302
+ $this->saveProcessors();
303
+ }
304
+
305
+ protected function deleteAllPluginDbOptions() {
306
+ if ( !current_user_can( 'manage_options' ) ) {
307
+ return;
308
+ }
309
+
310
+ $aOptions = $this->getAllOptionsHandlers();
311
+ foreach( $aOptions as &$oOption ) {
312
+ $oOption->deletePluginOptions();
313
+ }
314
+
315
+ $aFeatures = $this->getFeaturesMap();
316
+ foreach( $aFeatures as $sSlug => $sProcessorName ) {
317
+ $oProcessor = $this->getProcessorVar( $sProcessorName, true );
318
+ if ( !is_null($oProcessor) && is_object($oProcessor) ) {
319
+ $oProcessor->deleteAndCleanUp();
320
+ }
321
+ }
322
+ remove_action( 'shutdown', array( $this, 'onWpShutdown' ) );
323
+ }
324
+
325
+ public function onWpActivatePlugin() {
326
+ $this->loadOptionsHandler( 'all', true, true );
327
+ }
328
+
329
+ public function onWpDeactivatePlugin() {
330
+ if ( $this->m_oPluginMainOptions->getOpt( 'delete_on_deactivate' ) == 'Y' ) {
331
+ $this->deleteAllPluginDbOptions();
332
+ }
333
+ }
334
+
335
+ }
336
+
337
+ endif;
src/icwp-import-base-processor.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -21,7 +21,7 @@ require_once( dirname(__FILE__).'/icwp-data-processor.php' );
21
 
22
  if ( !class_exists('ICWP_ImportBaseProcessor') ):
23
 
24
- class ICWP_ImportBaseProcessor extends ICWP_BaseProcessor_WPSF {
25
 
26
  /**
27
  * The options prefix used by the target plugin
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
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
src/icwp-import-wpf2-processor.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -136,8 +136,8 @@ class ICWP_ImportWpf2Processor extends ICWP_ImportBaseProcessor {
136
  if ( empty( $aTargetIpWhitelist ) ) {
137
  $aTargetIpWhitelist = array();
138
  }
139
- $this->m_oFirewallOptions->setOpt( $this->m_aOptionsMap['WP_firewall_whitelisted_ip'], ICWP_DataProcessor::Add_New_Raw_Ips( $aTargetIpWhitelist, $aNewList ) );
140
- // $this->updateTargetOption( $this->m_aOptionsMap['WP_firewall_whitelisted_ip'], ICWP_DataProcessor::Add_New_Raw_Ips( $aTargetIpWhitelist, $aNewList ) );
141
 
142
  // Whitelisted Pages and Vars... maybe later :|
143
  }
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
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
  }
src/icwp-once.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
+ * All rights reserved.
5
+ *
6
+ * Version: 2013-12-17-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
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
+ if ( !class_exists('ICWP_Once_V1') ):
21
+
22
+ class ICWP_Once_V1 {
23
+ /**
24
+ * @var ICWP_WPSF_Once
25
+ */
26
+ protected static $oInstance = NULL;
27
+
28
+ /**
29
+ * @return ICWP_Once_V1
30
+ */
31
+ public static function & GetInstance( $insCalledClass = '' ) {
32
+ if ( is_null( self::$oInstance ) ) {
33
+ if ( function_exists( 'get_called_class' ) ) {
34
+ $sCalledClass = get_called_class();
35
+ self::$oInstance = new $sCalledClass();
36
+ }
37
+ else {
38
+ self::$oInstance = new $insCalledClass();
39
+ }
40
+ }
41
+ return self::$oInstance;
42
+ }
43
+ }
44
+
45
+ endif;
46
+
47
+ if ( !class_exists('ICWP_WPSF_Once') ):
48
+ class ICWP_WPSF_Once extends ICWP_Once_V1 { }
49
+ endif;
src/icwp-optionshandler-autoupdates.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -17,16 +17,16 @@
17
 
18
  require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
19
 
20
- if ( !class_exists('ICWP_OptionsHandler_AutoUpdates') ):
21
 
22
- class ICWP_OptionsHandler_AutoUpdates extends ICWP_OptionsHandler_Base_WPSF {
23
 
24
  const StoreName = 'autoupdates_options';
25
 
26
  public function __construct( $insPrefix, $insVersion ) {
27
  parent::__construct( $insPrefix, self::StoreName, $insVersion );
28
  }
29
-
30
  public function doPrePluginOptionsSave() {}
31
 
32
  public function defineOptions() {
@@ -37,11 +37,27 @@ class ICWP_OptionsHandler_AutoUpdates extends ICWP_OptionsHandler_Base_WPSF {
37
  array(
38
  'enable_autoupdates',
39
  '',
40
- 'N',
41
  'checkbox',
42
  _wpsf__( 'Enable Auto Updates' ),
43
  _wpsf__( 'Enable (or Disable) The Simple Firewall Automatic Updates Feature' ),
44
- _wpsf__( 'Regardless of any other settings, this option will turn off the Auto Updates feature, or enable your selected Auto Updates options.' )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  )
46
  )
47
  );
@@ -49,13 +65,14 @@ class ICWP_OptionsHandler_AutoUpdates extends ICWP_OptionsHandler_Base_WPSF {
49
  'section_title' => _wpsf__('Automatic Plugin Self-Update'),
50
  'section_options' => array(
51
  array(
52
- 'autoupdate_plugin_wpsf',
53
  '',
54
  'Y',
55
  'checkbox',
56
  _wpsf__( 'Auto Update Plugin' ),
57
  _wpsf__( 'Always Automatically Update This Plugin' ),
58
- _wpsf__( 'Regardless of any component settings below, automatically update the WordPress Simple Firewall plugin.' )
 
59
  )
60
  )
61
  );
@@ -74,7 +91,8 @@ class ICWP_OptionsHandler_AutoUpdates extends ICWP_OptionsHandler_Base_WPSF {
74
  $aAutoUpdateOptions,
75
  _wpsf__( 'WordPress Core Updates' ),
76
  _wpsf__( 'Decide how the WordPress Core will automatically update, if at all' ),
77
- _wpsf__( 'At least automatically upgrading minor versions is recommended (and is the WordPress default).' )
 
78
  ),
79
  array(
80
  'enable_autoupdate_translations',
@@ -114,17 +132,27 @@ class ICWP_OptionsHandler_AutoUpdates extends ICWP_OptionsHandler_Base_WPSF {
114
  )
115
  )
116
  );
117
- $aAutoUpdateAll = array(
118
- 'section_title' => _wpsf__('Disable ALL WordPress Automatic Updates'),
 
119
  'section_options' => array(
120
  array(
121
- 'enable_autoupdate_disable_all',
122
  '',
123
- 'N',
124
  'checkbox',
125
- _wpsf__( 'Disable All' ),
126
- _wpsf__( 'Completely Disable WordPress Automatic Updates' ),
127
- _wpsf__( 'When selected, regardless of any other settings, all WordPress automatic updates on this site will be completely disabled!' )
 
 
 
 
 
 
 
 
 
128
  )
129
  )
130
  );
@@ -134,15 +162,18 @@ class ICWP_OptionsHandler_AutoUpdates extends ICWP_OptionsHandler_Base_WPSF {
134
  $aAutoUpdateAll,
135
  $aAutoUpdatePlugin,
136
  $aAutoUpdateComponents,
 
137
  );
138
  }
139
 
140
  public function updateHandler() {
141
 
142
- $sCurrentVersion = empty( $this->m_aOptionsValues[ 'current_plugin_version' ] )? '0.0' : $this->m_aOptionsValues[ 'current_plugin_version' ];
143
- if ( version_compare( $sCurrentVersion, '1.9.0', '<' ) ) {
144
- }//v1.9.0
145
  }
146
  }
147
 
148
- endif;
 
 
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
17
 
18
  require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
19
 
20
+ if ( !class_exists('ICWP_OptionsHandler_AutoUpdates_V2') ):
21
 
22
+ class ICWP_OptionsHandler_AutoUpdates_V2 extends ICWP_OptionsHandler_Base_Wpsf {
23
 
24
  const StoreName = 'autoupdates_options';
25
 
26
  public function __construct( $insPrefix, $insVersion ) {
27
  parent::__construct( $insPrefix, self::StoreName, $insVersion );
28
  }
29
+
30
  public function doPrePluginOptionsSave() {}
31
 
32
  public function defineOptions() {
37
  array(
38
  'enable_autoupdates',
39
  '',
40
+ 'Y',
41
  'checkbox',
42
  _wpsf__( 'Enable Auto Updates' ),
43
  _wpsf__( 'Enable (or Disable) The Simple Firewall Automatic Updates Feature' ),
44
+ sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('Automatic Updates') ),
45
+ '<a href="http://icwp.io/3w" target="_blank">'._wpsf__( 'more info' ).'</a>'
46
+ )
47
+ )
48
+ );
49
+ $aAutoUpdateAll = array(
50
+ 'section_title' => _wpsf__('Disable ALL WordPress Automatic Updates'),
51
+ 'section_options' => array(
52
+ array(
53
+ 'enable_autoupdate_disable_all',
54
+ '',
55
+ 'N',
56
+ 'checkbox',
57
+ _wpsf__( 'Disable All' ),
58
+ _wpsf__( 'Completely Disable WordPress Automatic Updates' ),
59
+ _wpsf__( 'When selected, regardless of any other settings, all WordPress automatic updates on this site will be completely disabled!' ),
60
+ '<a href="http://icwp.io/3v" target="_blank">'._wpsf__( 'more info' ).'</a>'
61
  )
62
  )
63
  );
65
  'section_title' => _wpsf__('Automatic Plugin Self-Update'),
66
  'section_options' => array(
67
  array(
68
+ 'autoupdate_plugin_self',
69
  '',
70
  'Y',
71
  'checkbox',
72
  _wpsf__( 'Auto Update Plugin' ),
73
  _wpsf__( 'Always Automatically Update This Plugin' ),
74
+ _wpsf__( 'Regardless of any component settings below, automatically update the WordPress Simple Firewall plugin.' ),
75
+ '<a href="http://icwp.io/3u" target="_blank">'._wpsf__( 'more info' ).'</a>'
76
  )
77
  )
78
  );
91
  $aAutoUpdateOptions,
92
  _wpsf__( 'WordPress Core Updates' ),
93
  _wpsf__( 'Decide how the WordPress Core will automatically update, if at all' ),
94
+ _wpsf__( 'At least automatically upgrading minor versions is recommended (and is the WordPress default).' ),
95
+ '<a href="http://icwp.io/3x" target="_blank">'._wpsf__( 'more info' ).'</a>'
96
  ),
97
  array(
98
  'enable_autoupdate_translations',
132
  )
133
  )
134
  );
135
+
136
+ $aAutoUpdateEmail = array(
137
+ 'section_title' => _wpsf__('Automatic Update Email Notifications'),
138
  'section_options' => array(
139
  array(
140
+ 'enable_upgrade_notification_email',
141
  '',
142
+ 'Y',
143
  'checkbox',
144
+ _wpsf__( 'Send Report Email' ),
145
+ _wpsf__( 'Send email notices after automatic updates' ),
146
+ _wpsf__( 'You can turn on/off email notices from automatic updates by un/checking this box.' )
147
+ ),
148
+ array(
149
+ 'override_email_address',
150
+ '',
151
+ '',
152
+ 'email',
153
+ _wpsf__( 'Report Email Address' ),
154
+ _wpsf__( 'Where to send upgrade notification reports' ),
155
+ _wpsf__( 'If this is empty, it will default to the Site admin email address' )
156
  )
157
  )
158
  );
162
  $aAutoUpdateAll,
163
  $aAutoUpdatePlugin,
164
  $aAutoUpdateComponents,
165
+ $aAutoUpdateEmail
166
  );
167
  }
168
 
169
  public function updateHandler() {
170
 
171
+ $sCurrentVersion = $this->getVersion();
172
+ $sCurrentVersion = empty( $sCurrentVersion )? '0.0' : $sCurrentVersion;
173
+ if ( version_compare( $sCurrentVersion, '1.9.0', '<' ) ) { }//v1.9.0
174
  }
175
  }
176
 
177
+ endif;
178
+
179
+ class ICWP_OptionsHandler_AutoUpdates extends ICWP_OptionsHandler_AutoUpdates_V2 { }
src/icwp-optionshandler-base.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
- * Version: 2013-08-27-A
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
@@ -17,11 +17,18 @@
17
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
  */
19
 
20
- if ( !class_exists('ICWP_OptionsHandler_Base_WPSF') ):
21
 
22
- class ICWP_OptionsHandler_Base_WPSF {
23
 
 
 
 
24
  const CollateSeparator = '--SEP--';
 
 
 
 
25
 
26
  /**
27
  * @var boolean
@@ -57,16 +64,7 @@ class ICWP_OptionsHandler_Base_WPSF {
57
  * @var boolean
58
  */
59
  protected $m_fIsMultisite;
60
-
61
- /**
62
- * This is used primarily for the options deletion/cleanup. We store the names
63
- * of options here that are not modified directly by the user/UI so that we can
64
- * cleanup later on.
65
- *
66
- * @var array
67
- */
68
- protected $m_aIndependentOptions;
69
-
70
  /**
71
  * These are options that need to be stored, but are never set by the UI.
72
  *
@@ -84,6 +82,11 @@ class ICWP_OptionsHandler_Base_WPSF {
84
  */
85
  protected $m_aOptionsStoreName;
86
 
 
 
 
 
 
87
  public function __construct( $insPrefix, $insStoreName, $insVersion ) {
88
  $this->m_sOptionPrefix = $insPrefix;
89
  $this->m_aOptionsStoreName = $insStoreName;
@@ -92,10 +95,17 @@ class ICWP_OptionsHandler_Base_WPSF {
92
  $this->m_fIsMultisite = function_exists( 'is_multisite' ) && is_multisite();
93
 
94
  // Handle any upgrades as necessary (only go near this if it's the admin area)
95
- add_action( 'plugins_loaded', array( $this, 'doUpdates' ) );
96
  }
97
 
98
- public function doUpdates() {
 
 
 
 
 
 
 
99
  if ( $this->hasPluginManageRights() ) {
100
  $this->buildOptions();
101
  $this->updateHandler();
@@ -119,14 +129,49 @@ class ICWP_OptionsHandler_Base_WPSF {
119
  * @return string
120
  */
121
  public function getVersion() {
122
- return $this->m_sVersion;
123
  }
124
 
125
  /**
 
126
  * @return string
127
  */
128
  public function setVersion( $insVersion ) {
129
- return $this->m_sVersion = $insVersion;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  }
131
 
132
  /**
@@ -138,6 +183,10 @@ class ICWP_OptionsHandler_Base_WPSF {
138
  */
139
  public function setOpt( $insKey, $inmValue ) {
140
 
 
 
 
 
141
  if ( !isset( $this->m_aOptionsValues ) ) {
142
  $this->loadStoredOptionsValues();
143
  }
@@ -171,9 +220,7 @@ class ICWP_OptionsHandler_Base_WPSF {
171
  * @return array
172
  */
173
  public function getOptions() {
174
- if ( !isset( $this->m_aOptions ) ) {
175
- $this->buildOptions();
176
- }
177
  return $this->m_aOptions;
178
  }
179
 
@@ -196,20 +243,10 @@ class ICWP_OptionsHandler_Base_WPSF {
196
 
197
  $this->doPrePluginOptionsSave();
198
  $this->updateOptionsVersion();
199
-
200
  if ( !$this->m_fNeedSave ) {
201
  return true;
202
  }
203
-
204
  $this->updateOption( $this->m_aOptionsStoreName, $this->m_aOptionsValues );
205
-
206
- // Direct save options allow us to get fast access to certain values without loading the whole thing
207
- if ( isset( $this->m_aDirectSaveOptions ) && is_array( $this->m_aDirectSaveOptions ) ) {
208
- foreach( $this->m_aDirectSaveOptions as $sOptionKey ) {
209
- $this->updateOption( $sOptionKey, $this->getOpt( $sOptionKey ) );
210
- }
211
- }
212
-
213
  $this->m_fNeedSave = false;
214
  }
215
 
@@ -293,11 +330,12 @@ class ICWP_OptionsHandler_Base_WPSF {
293
  *
294
  * @param string $insUpdateKey - if only want to update a single key, supply it here.
295
  */
296
- protected function buildOptions() {
297
 
298
  $this->defineOptions();
299
  $this->loadStoredOptionsValues();
300
 
 
301
  foreach ( $this->m_aOptions as &$aOptionsSection ) {
302
 
303
  if ( empty( $aOptionsSection ) || !isset( $aOptionsSection['section_options'] ) ) {
@@ -307,7 +345,9 @@ class ICWP_OptionsHandler_Base_WPSF {
307
  foreach ( $aOptionsSection['section_options'] as &$aOptionParams ) {
308
 
309
  list( $sOptionKey, $sOptionValue, $sOptionDefault, $sOptionType ) = $aOptionParams;
310
-
 
 
311
  if ( $this->getOpt( $sOptionKey ) === false ) {
312
  $this->setOpt( $sOptionKey, $sOptionDefault );
313
  }
@@ -325,6 +365,19 @@ class ICWP_OptionsHandler_Base_WPSF {
325
  $mCurrentOptionVal = implode( "\n", $this->convertIpListForDisplay( $mCurrentOptionVal ) );
326
  }
327
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  else if ( $sOptionType == 'comma_separated_lists' ) {
329
 
330
  if ( empty( $mCurrentOptionVal ) ) {
@@ -345,6 +398,7 @@ class ICWP_OptionsHandler_Base_WPSF {
345
  // Cater for Non-UI options that don't necessarily go through the UI
346
  if ( isset($this->m_aNonUiOptions) && is_array($this->m_aNonUiOptions) ) {
347
  foreach( $this->m_aNonUiOptions as $sOption ) {
 
348
  if ( !$this->getOpt( $sOption ) ) {
349
  $this->setOpt( $sOption, '' );
350
  }
@@ -378,23 +432,9 @@ class ICWP_OptionsHandler_Base_WPSF {
378
  * Deletes all the options including direct save.
379
  */
380
  public function deletePluginOptions() {
381
-
382
  $this->deleteOption( $this->m_aOptionsStoreName );
383
-
384
- // Direct save options allow us to get fast access to certain values without loading the whole thing
385
- if ( isset($this->m_aDirectSaveOptions) && is_array( $this->m_aDirectSaveOptions ) ) {
386
- foreach( $this->m_aDirectSaveOptions as $sOptionKey ) {
387
- $this->deleteOption( $sOptionKey );
388
- }
389
- }
390
- // Independent options are those untouched by the User/UI that are saved elsewhere and directly to the WP Options table. They are "meta" options
391
- if ( isset($this->m_aIndependentOptions) && is_array( $this->m_aIndependentOptions ) ) {
392
- foreach( $this->m_aIndependentOptions as $sOptionKey ) {
393
- $this->deleteOption( $sOptionKey );
394
- }
395
- }
396
  }
397
-
398
  protected function convertIpListForDisplay( $inaIpList = array() ) {
399
 
400
  $aDisplay = array();
@@ -426,6 +466,9 @@ class ICWP_OptionsHandler_Base_WPSF {
426
  * @return void|boolean
427
  */
428
  public function updatePluginOptionsFromSubmit( $sAllOptionsInput ) {
 
 
 
429
 
430
  if ( empty( $sAllOptionsInput ) ) {
431
  return;
@@ -437,6 +480,10 @@ class ICWP_OptionsHandler_Base_WPSF {
437
  foreach ( $aAllInputOptions as $sInputKey ) {
438
  $aInput = explode( ':', $sInputKey );
439
  list( $sOptionType, $sOptionKey ) = $aInput;
 
 
 
 
440
 
441
  $sOptionValue = $this->getFromPost( $sOptionKey );
442
  if ( is_null($sOptionValue) ) {
@@ -464,21 +511,15 @@ class ICWP_OptionsHandler_Base_WPSF {
464
  $sOptionValue = md5( $sTempValue );
465
  }
466
  else if ( $sOptionType == 'ip_addresses' ) { //ip addresses are textareas, where each is separated by newline
467
-
468
- if ( !class_exists('ICWP_DataProcessor') ) {
469
- require_once ( dirname(__FILE__).'/icwp-data-processor.php' );
470
- }
471
- $oProcessor = new ICWP_DataProcessor();
472
  $sOptionValue = $oProcessor->ExtractIpAddresses( $sOptionValue );
473
  }
 
 
 
474
  else if ( $sOptionType == 'email' && function_exists( 'is_email' ) && !is_email( $sOptionValue ) ) {
475
  $sOptionValue = '';
476
  }
477
  else if ( $sOptionType == 'comma_separated_lists' ) {
478
- if ( !class_exists('ICWP_DataProcessor') ) {
479
- require_once ( dirname(__FILE__).'/icwp-data-processor.php' );
480
- }
481
- $oProcessor = new ICWP_DataProcessor();
482
  $sOptionValue = $oProcessor->ExtractCommaSeparatedList( $sOptionValue );
483
  }
484
  }
@@ -535,8 +576,8 @@ class ICWP_OptionsHandler_Base_WPSF {
535
  }
536
 
537
  protected function getVisitorIpAddress( $infAsLong = true ) {
538
- require_once( dirname(__FILE__).'/icwp-base-processor.php' );
539
- return ICWP_BaseProcessor_WPSF::GetVisitorIpAddress( $infAsLong );
540
  }
541
 
542
  /**
@@ -564,6 +605,61 @@ class ICWP_OptionsHandler_Base_WPSF {
564
  $sKey = $this->m_sOptionPrefix.$insKey;
565
  return $this->m_fIsMultisite? delete_site_option($sKey) : delete_option($sKey);
566
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
567
  }
568
 
569
- endif;
 
 
1
  <?php
2
  /**
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
17
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
  */
19
 
20
+ if ( !class_exists('ICWP_OptionsHandler_Base_V2') ):
21
 
22
+ class ICWP_OptionsHandler_Base_V2 {
23
 
24
+ /**
25
+ * @var string
26
+ */
27
  const CollateSeparator = '--SEP--';
28
+ /**
29
+ * @var string
30
+ */
31
+ const PluginVersionKey = 'current_plugin_version';
32
 
33
  /**
34
  * @var boolean
64
  * @var boolean
65
  */
66
  protected $m_fIsMultisite;
67
+
 
 
 
 
 
 
 
 
 
68
  /**
69
  * These are options that need to be stored, but are never set by the UI.
70
  *
82
  */
83
  protected $m_aOptionsStoreName;
84
 
85
+ /**
86
+ * @var array
87
+ */
88
+ protected $aOptionsKeys;
89
+
90
  public function __construct( $insPrefix, $insStoreName, $insVersion ) {
91
  $this->m_sOptionPrefix = $insPrefix;
92
  $this->m_aOptionsStoreName = $insStoreName;
95
  $this->m_fIsMultisite = function_exists( 'is_multisite' ) && is_multisite();
96
 
97
  // Handle any upgrades as necessary (only go near this if it's the admin area)
98
+ add_action( 'init', array( $this, 'onWpPluginsLoaded' ), 1 );
99
  }
100
 
101
+ /**
102
+ * A action added to WordPress 'plugins_loaded' hook
103
+ */
104
+ public function onWpPluginsLoaded() {
105
+ $this->doUpdates();
106
+ }
107
+
108
+ protected function doUpdates() {
109
  if ( $this->hasPluginManageRights() ) {
110
  $this->buildOptions();
111
  $this->updateHandler();
129
  * @return string
130
  */
131
  public function getVersion() {
132
+ return $this->getOpt( self::PluginVersionKey );
133
  }
134
 
135
  /**
136
+ * @param string
137
  * @return string
138
  */
139
  public function setVersion( $insVersion ) {
140
+ return $this->setOpt( self::PluginVersionKey, $insVersion );
141
+ }
142
+
143
+ /**
144
+ * Gets the array of all possible options keys
145
+ *
146
+ * @return array
147
+ */
148
+ public function getOptionsKeys() {
149
+ $this->setOptionsKeys();
150
+ return $this->aOptionsKeys;
151
+ }
152
+
153
+ /**
154
+ * @return void
155
+ */
156
+ public function setOptionsKeys() {
157
+ if ( !empty( $this->aOptionsKeys ) ) {
158
+ return;
159
+ }
160
+ $this->buildOptions();
161
+ }
162
+
163
+ /**
164
+ * Determines whether the given option key is a valid options
165
+ *
166
+ * @param string
167
+ * @return boolean
168
+ */
169
+ public function getIsOptionKey( $sOptionKey ) {
170
+ if ( $sOptionKey == self::PluginVersionKey ) {
171
+ return true;
172
+ }
173
+ $this->setOptionsKeys();
174
+ return ( in_array( $sOptionKey, $this->aOptionsKeys ) );
175
  }
176
 
177
  /**
183
  */
184
  public function setOpt( $insKey, $inmValue ) {
185
 
186
+ if ( !$this->getIsOptionKey( $insKey ) ) {
187
+ return false;
188
+ }
189
+
190
  if ( !isset( $this->m_aOptionsValues ) ) {
191
  $this->loadStoredOptionsValues();
192
  }
220
  * @return array
221
  */
222
  public function getOptions() {
223
+ $this->buildOptions();
 
 
224
  return $this->m_aOptions;
225
  }
226
 
243
 
244
  $this->doPrePluginOptionsSave();
245
  $this->updateOptionsVersion();
 
246
  if ( !$this->m_fNeedSave ) {
247
  return true;
248
  }
 
249
  $this->updateOption( $this->m_aOptionsStoreName, $this->m_aOptionsValues );
 
 
 
 
 
 
 
 
250
  $this->m_fNeedSave = false;
251
  }
252
 
330
  *
331
  * @param string $insUpdateKey - if only want to update a single key, supply it here.
332
  */
333
+ public function buildOptions() {
334
 
335
  $this->defineOptions();
336
  $this->loadStoredOptionsValues();
337
 
338
+ $this->aOptionsKeys = array();
339
  foreach ( $this->m_aOptions as &$aOptionsSection ) {
340
 
341
  if ( empty( $aOptionsSection ) || !isset( $aOptionsSection['section_options'] ) ) {
345
  foreach ( $aOptionsSection['section_options'] as &$aOptionParams ) {
346
 
347
  list( $sOptionKey, $sOptionValue, $sOptionDefault, $sOptionType ) = $aOptionParams;
348
+
349
+ $this->aOptionsKeys[] = $sOptionKey;
350
+
351
  if ( $this->getOpt( $sOptionKey ) === false ) {
352
  $this->setOpt( $sOptionKey, $sOptionDefault );
353
  }
365
  $mCurrentOptionVal = implode( "\n", $this->convertIpListForDisplay( $mCurrentOptionVal ) );
366
  }
367
  }
368
+ else if ( $sOptionType == 'yubikey_unique_keys' ) {
369
+
370
+ if ( empty( $mCurrentOptionVal ) ) {
371
+ $mCurrentOptionVal = '';
372
+ }
373
+ else {
374
+ $aDisplay = array();
375
+ foreach( $mCurrentOptionVal as $aParts ) {
376
+ $aDisplay[] = key($aParts) .', '. reset($aParts);
377
+ }
378
+ $mCurrentOptionVal = implode( "\n", $aDisplay );
379
+ }
380
+ }
381
  else if ( $sOptionType == 'comma_separated_lists' ) {
382
 
383
  if ( empty( $mCurrentOptionVal ) ) {
398
  // Cater for Non-UI options that don't necessarily go through the UI
399
  if ( isset($this->m_aNonUiOptions) && is_array($this->m_aNonUiOptions) ) {
400
  foreach( $this->m_aNonUiOptions as $sOption ) {
401
+ $this->aOptionsKeys[] = $sOption;
402
  if ( !$this->getOpt( $sOption ) ) {
403
  $this->setOpt( $sOption, '' );
404
  }
432
  * Deletes all the options including direct save.
433
  */
434
  public function deletePluginOptions() {
 
435
  $this->deleteOption( $this->m_aOptionsStoreName );
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  }
437
+
438
  protected function convertIpListForDisplay( $inaIpList = array() ) {
439
 
440
  $aDisplay = array();
466
  * @return void|boolean
467
  */
468
  public function updatePluginOptionsFromSubmit( $sAllOptionsInput ) {
469
+
470
+ require_once ( dirname(__FILE__).'/icwp-data-processor.php' );
471
+ $oProcessor = new ICWP_WPSF_DataProcessor();
472
 
473
  if ( empty( $sAllOptionsInput ) ) {
474
  return;
480
  foreach ( $aAllInputOptions as $sInputKey ) {
481
  $aInput = explode( ':', $sInputKey );
482
  list( $sOptionType, $sOptionKey ) = $aInput;
483
+
484
+ if ( !$this->getIsOptionKey( $sOptionKey ) ) {
485
+ continue;
486
+ }
487
 
488
  $sOptionValue = $this->getFromPost( $sOptionKey );
489
  if ( is_null($sOptionValue) ) {
511
  $sOptionValue = md5( $sTempValue );
512
  }
513
  else if ( $sOptionType == 'ip_addresses' ) { //ip addresses are textareas, where each is separated by newline
 
 
 
 
 
514
  $sOptionValue = $oProcessor->ExtractIpAddresses( $sOptionValue );
515
  }
516
+ else if ( $sOptionType == 'yubikey_unique_keys' ) { //ip addresses are textareas, where each is separated by newline and are 12 chars long
517
+ $sOptionValue = $oProcessor->CleanYubikeyUniqueKeys( $sOptionValue );
518
+ }
519
  else if ( $sOptionType == 'email' && function_exists( 'is_email' ) && !is_email( $sOptionValue ) ) {
520
  $sOptionValue = '';
521
  }
522
  else if ( $sOptionType == 'comma_separated_lists' ) {
 
 
 
 
523
  $sOptionValue = $oProcessor->ExtractCommaSeparatedList( $sOptionValue );
524
  }
525
  }
576
  }
577
 
578
  protected function getVisitorIpAddress( $infAsLong = true ) {
579
+ require_once( dirname(__FILE__).'/icwp-data-processor.php' );
580
+ return ICWP_WPSF_DataProcessor::GetVisitorIpAddress( $infAsLong );
581
  }
582
 
583
  /**
605
  $sKey = $this->m_sOptionPrefix.$insKey;
606
  return $this->m_fIsMultisite? delete_site_option($sKey) : delete_option($sKey);
607
  }
608
+
609
+
610
+ /**
611
+ * @param string $insExistingListKey
612
+ * @param string $insFilterName
613
+ * @return array|false
614
+ */
615
+ protected function processIpFilter( $insExistingListKey, $insFilterName ) {
616
+ $aFilterIps = apply_filters( $insFilterName, array() );
617
+ if ( empty( $aFilterIps ) ) {
618
+ return false;
619
+ }
620
+
621
+ $aNewIps = array();
622
+ foreach( $aFilterIps as $mKey => $sValue ) {
623
+ if ( is_string( $mKey ) ) { //it's the IP
624
+ $sIP = $mKey;
625
+ $sLabel = $sValue;
626
+ }
627
+ else { //it's not an associative array, so the value is the IP
628
+ $sIP = $sValue;
629
+ $sLabel = '';
630
+ }
631
+ $aNewIps[ $sIP ] = $sLabel;
632
+ }
633
+
634
+ // now add and store the new IPs
635
+ $aExistingIpList = $this->getOpt( $insExistingListKey );
636
+ if ( !is_array( $aExistingIpList ) ) {
637
+ $aExistingIpList = array();
638
+ }
639
+
640
+ $this->loadDataProcessor();
641
+ $nNewAddedCount = 0;
642
+ $aNewList = ICWP_WPSF_DataProcessor::Add_New_Raw_Ips( $aExistingIpList, $aNewIps, $nNewAddedCount );
643
+ if ( $nNewAddedCount > 0 ) {
644
+ $this->setOpt( $insExistingListKey, $aNewList );
645
+ }
646
+ }
647
+
648
+ protected function loadDataProcessor() {
649
+ if ( !class_exists('ICWP_WPSF_DataProcessor') ) {
650
+ require_once( dirname(__FILE__).'/icwp-data-processor.php' );
651
+ }
652
+ }
653
+
654
+ /**
655
+ * @return ICWP_WpFilesystem_WPSF
656
+ */
657
+ protected function loadFileSystemProcessor() {
658
+ require_once( dirname(__FILE__) . '/icwp-wpfilesystem.php' );
659
+ return ICWP_WpFilesystem_WPSF::GetInstance();
660
+ }
661
  }
662
 
663
+ endif;
664
+
665
+ class ICWP_OptionsHandler_Base_Wpsf extends ICWP_OptionsHandler_Base_V2 { }
src/icwp-optionshandler-commentsfilter.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -19,7 +19,7 @@ require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
19
 
20
  if ( !class_exists('ICWP_OptionsHandler_CommentsFilter') ):
21
 
22
- class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_WPSF {
23
 
24
  const StoreName = 'commentsfilter_options';
25
 
@@ -29,27 +29,67 @@ class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_WPSF {
29
  public function __construct( $insPrefix, $insVersion ) {
30
  parent::__construct( $insPrefix, self::StoreName, $insVersion );
31
  }
32
-
 
 
 
33
  public function defineOptions() {
34
 
35
- $this->m_aDirectSaveOptions = array();
36
-
37
  $aBase = array(
38
- 'section_title' => _wpsf__( 'Enable Comments Filter' ),
39
  'section_options' => array(
40
  array(
41
  'enable_comments_filter',
42
  '',
43
- 'Y',
44
  'checkbox',
45
  _wpsf__( 'Enable Comments Filter' ),
46
- _wpsf__( 'Enable (or Disable) The SPAM Comments Filter Feature.' ),
47
- _wpsf__( 'Regardless of any other settings, this option will turn off the Comments Filter feature, or enable your chosen Comments Filter options.' )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  )
49
  ),
50
  );
 
51
  $aGasp = array(
52
- 'section_title' => _wpsf__( 'G.A.S.P. Comment SPAM Protection' ),
53
  'section_options' => array(
54
  array(
55
  'enable_comments_gasp_protection',
@@ -58,8 +98,19 @@ class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_WPSF {
58
  'checkbox',
59
  _wpsf__( 'GASP Protection' ),
60
  _wpsf__( 'Add Growmap Anti Spambot Protection to your comments' ),
61
- _wpsf__( 'Taking the lead from the original GASP plugin for WordPress, we have extended it to include further protection.' )
62
- .' '.sprintf( _wpsf__( '%smore info%s' ), '[<a href="http://icwp.io/2n" target="_blank">', '</a>]' )
 
 
 
 
 
 
 
 
 
 
 
63
  ),
64
  array(
65
  'enable_comments_gasp_protection_for_logged_in',
@@ -77,7 +128,8 @@ class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_WPSF {
77
  'integer',
78
  _wpsf__( 'Comments Cooldown' ),
79
  _wpsf__( 'Limit posting comments to X seconds after the page has loaded' ),
80
- _wpsf__( "By forcing a comments cooldown period, you restrict a Spambot's ability to post mutliple times to your posts." )
 
81
  ),
82
  array(
83
  'comments_token_expire_interval',
@@ -86,9 +138,16 @@ class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_WPSF {
86
  'integer',
87
  _wpsf__( 'Comment Token Expire' ),
88
  _wpsf__( 'A visitor has X seconds within which to post a comment' ),
89
- _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." )
90
-
91
- ),
 
 
 
 
 
 
 
92
  array(
93
  'custom_message_checkbox',
94
  '',
@@ -97,7 +156,8 @@ class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_WPSF {
97
  _wpsf__( 'Custom Checkbox Message' ),
98
  _wpsf__( 'If you want a custom checkbox message, please provide this here' ),
99
  _wpsf__( "You can customise the message beside the checkbox." )
100
- .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please check the box to confirm you're not a spammer") )
 
101
  ),
102
  array(
103
  'custom_message_alert',
@@ -107,7 +167,8 @@ class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_WPSF {
107
  _wpsf__( 'Custom Alert Message' ),
108
  _wpsf__( 'If you want a custom alert message, please provide this here' ),
109
  _wpsf__( "This alert message is displayed when a visitor attempts to submit a comment without checking the box." )
110
- .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please check the box to confirm you're not a spammer") )
 
111
  ),
112
  array(
113
  'custom_message_comment_wait',
@@ -117,7 +178,8 @@ class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_WPSF {
117
  _wpsf__( 'Custom Wait Message' ),
118
  _wpsf__( 'If you want a custom submit-button wait message, please provide this here.' ),
119
  _wpsf__( "Where you see the '%s' this will be the number of seconds. You must ensure you include 1, and only 1, of these." )
120
- .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__('Please wait %s seconds before posting your comment') )
 
121
  ),
122
  array(
123
  'custom_message_comment_reload',
@@ -127,14 +189,17 @@ class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_WPSF {
127
  _wpsf__( 'Custom Reload Message' ),
128
  _wpsf__( 'If you want a custom message when the comment token has expired, please provide this here.' ),
129
  _wpsf__( 'This message is displayed on the submit-button when the comment token is expired' )
130
- .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please reload this page to post a comment") )
 
131
  )
132
  )
133
  );
134
 
135
  $this->m_aOptions = array(
136
  $aBase,
137
- $aGasp
 
 
138
  );
139
  }
140
 
@@ -159,6 +224,42 @@ class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_WPSF {
159
  }
160
  $this->setOpt( 'comments_cooldown_interval', $nCommentCooldown );
161
  $this->setOpt( 'comments_token_expire_interval', $nCommentTokenExpire );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  }
163
 
164
  public function updateHandler() {
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
19
 
20
  if ( !class_exists('ICWP_OptionsHandler_CommentsFilter') ):
21
 
22
+ class ICWP_OptionsHandler_CommentsFilter extends ICWP_OptionsHandler_Base_Wpsf {
23
 
24
  const StoreName = 'commentsfilter_options';
25
 
29
  public function __construct( $insPrefix, $insVersion ) {
30
  parent::__construct( $insPrefix, self::StoreName, $insVersion );
31
  }
32
+
33
+ /**
34
+ * @return bool|void
35
+ */
36
  public function defineOptions() {
37
 
 
 
38
  $aBase = array(
39
+ 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('SPAM Comments Protection Filter') ),
40
  'section_options' => array(
41
  array(
42
  'enable_comments_filter',
43
  '',
44
+ 'N',
45
  'checkbox',
46
  _wpsf__( 'Enable Comments Filter' ),
47
+ _wpsf__( 'Enable (or Disable) The SPAM Comments Protection Filter Feature' ),
48
+ sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('SPAM Comments Protection Filter') ),
49
+ '<a href="http://icwp.io/3z" target="_blank">'._wpsf__( 'more info' ).'</a>'
50
+ .' | <a href="http://icwp.io/wpsf04" target="_blank">'._wpsf__( 'blog' ).'</a>'
51
+ )
52
+ )
53
+ );
54
+
55
+ $aHumanSpam = array(
56
+ 'section_title' => sprintf( _wpsf__( '%s Comment SPAM Protection Filter' ), _wpsf__('Human') ),
57
+ 'section_options' => array(
58
+ array(
59
+ 'enable_comments_human_spam_filter',
60
+ '',
61
+ 'N',
62
+ 'checkbox',
63
+ _wpsf__( 'Human SPAM Filter' ),
64
+ _wpsf__( 'Enable (or Disable) The Human SPAM Filter Feature.' ),
65
+ _wpsf__( 'Scans the content of WordPress comments for keywords that are indicative of SPAM and marks the comment according to your preferred setting below.' ),
66
+ '<a href="http://icwp.io/57" target="_blank">'._wpsf__( 'more info' ).'</a>'
67
+ ),
68
+ array(
69
+ 'enable_comments_human_spam_filter_items',
70
+ '',
71
+ $this->getHumanSpamFilterItems( true ),
72
+ $this->getHumanSpamFilterItems(),
73
+ _wpsf__( 'Comment Filter Items' ),
74
+ _wpsf__( 'Select The Items To Scan For SPAM' ),
75
+ _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') ),
76
+ '<a href="http://icwp.io/58" target="_blank">'._wpsf__( 'more info' ).'</a>'
77
+ ),
78
+ array(
79
+ 'comments_default_action_human_spam',
80
+ '',
81
+ 'spam',
82
+ $this->getSpamHandlingResponses(),
83
+ _wpsf__( 'Default SPAM Action' ),
84
+ _wpsf__( 'How To Categorise Comments When Identified To Be SPAM' ),
85
+ 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>' ),
86
+ '<a href="http://icwp.io/59" target="_blank">'._wpsf__( 'more info' ).'</a>'
87
  )
88
  ),
89
  );
90
+
91
  $aGasp = array(
92
+ 'section_title' => sprintf( _wpsf__( '%s Comment SPAM Protection Filter' ), _wpsf__('Automatic Bot') ),
93
  'section_options' => array(
94
  array(
95
  'enable_comments_gasp_protection',
98
  'checkbox',
99
  _wpsf__( 'GASP Protection' ),
100
  _wpsf__( 'Add Growmap Anti Spambot Protection to your comments' ),
101
+ _wpsf__( 'Taking the lead from the original GASP plugin for WordPress, we have extended it to include advanced spam-bot protection.' ),
102
+ '<a href="http://icwp.io/3n" target="_blank">'._wpsf__( 'more info' ).'</a>'
103
+ .' | <a href="http://icwp.io/2n" target="_blank">'._wpsf__( 'blog' ).'</a>'
104
+ ),
105
+ array(
106
+ 'comments_default_action_spam_bot',
107
+ '',
108
+ 'trash',
109
+ $this->getSpamHandlingResponses(),
110
+ _wpsf__( 'Default SPAM Action' ),
111
+ _wpsf__( 'How To Categorise Comments When Identified To Be SPAM' ),
112
+ 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>' ),
113
+ '<a href="http://icwp.io/59" target="_blank">'._wpsf__( 'more info' ).'</a>'
114
  ),
115
  array(
116
  'enable_comments_gasp_protection_for_logged_in',
128
  'integer',
129
  _wpsf__( 'Comments Cooldown' ),
130
  _wpsf__( 'Limit posting comments to X seconds after the page has loaded' ),
131
+ _wpsf__( "By forcing a comments cooldown period, you restrict a Spambot's ability to post mutliple times to your posts." ),
132
+ '<a href="http://icwp.io/3o" target="_blank">'._wpsf__( 'more info' ).'</a>'
133
  ),
134
  array(
135
  'comments_token_expire_interval',
138
  'integer',
139
  _wpsf__( 'Comment Token Expire' ),
140
  _wpsf__( 'A visitor has X seconds within which to post a comment' ),
141
+ _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." ),
142
+ '<a href="http://icwp.io/3o" target="_blank">'._wpsf__( 'more info' ).'</a>'
143
+
144
+ )
145
+ )
146
+ );
147
+
148
+ $aCustomMessages = array(
149
+ 'section_title' => sprintf( _wpsf__( 'Customize Messages Shown To User' ), _wpsf__('Automatic Bot') ),
150
+ 'section_options' => array(
151
  array(
152
  'custom_message_checkbox',
153
  '',
156
  _wpsf__( 'Custom Checkbox Message' ),
157
  _wpsf__( 'If you want a custom checkbox message, please provide this here' ),
158
  _wpsf__( "You can customise the message beside the checkbox." )
159
+ .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please check the box to confirm you're not a spammer") ),
160
+ '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
161
  ),
162
  array(
163
  'custom_message_alert',
167
  _wpsf__( 'Custom Alert Message' ),
168
  _wpsf__( 'If you want a custom alert message, please provide this here' ),
169
  _wpsf__( "This alert message is displayed when a visitor attempts to submit a comment without checking the box." )
170
+ .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please check the box to confirm you're not a spammer") ),
171
+ '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
172
  ),
173
  array(
174
  'custom_message_comment_wait',
178
  _wpsf__( 'Custom Wait Message' ),
179
  _wpsf__( 'If you want a custom submit-button wait message, please provide this here.' ),
180
  _wpsf__( "Where you see the '%s' this will be the number of seconds. You must ensure you include 1, and only 1, of these." )
181
+ .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__('Please wait %s seconds before posting your comment') ),
182
+ '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
183
  ),
184
  array(
185
  'custom_message_comment_reload',
189
  _wpsf__( 'Custom Reload Message' ),
190
  _wpsf__( 'If you want a custom message when the comment token has expired, please provide this here.' ),
191
  _wpsf__( 'This message is displayed on the submit-button when the comment token is expired' )
192
+ .'<br />'.sprintf( _wpsf__( 'Default Message: %s' ), _wpsf__("Please reload this page to post a comment") ),
193
+ '<a href="http://icwp.io/3p" target="_blank">'._wpsf__( 'more info' ).'</a>'
194
  )
195
  )
196
  );
197
 
198
  $this->m_aOptions = array(
199
  $aBase,
200
+ $aHumanSpam,
201
+ $aGasp,
202
+ $aCustomMessages
203
  );
204
  }
205
 
224
  }
225
  $this->setOpt( 'comments_cooldown_interval', $nCommentCooldown );
226
  $this->setOpt( 'comments_token_expire_interval', $nCommentTokenExpire );
227
+
228
+ $aCommentsFilters = $this->getOpt( 'enable_comments_human_spam_filter_items' );
229
+ if ( empty($aCommentsFilters) || !is_array( $aCommentsFilters ) ) {
230
+ $this->setOpt( 'enable_comments_human_spam_filter_items', $this->getHumanSpamFilterItems( true ) );
231
+ }
232
+ }
233
+
234
+ /**
235
+ * @return array
236
+ */
237
+ protected function getSpamHandlingResponses() {
238
+ return array( 'select',
239
+ array( 0, _wpsf__( 'Mark As Pending Moderation' ) ),
240
+ array( 'spam', _wpsf__( 'Mark As SPAM' ) ),
241
+ array( 'trash', _wpsf__( 'Move To Trash' ) ),
242
+ array( 'reject', _wpsf__( 'Reject And Redirect' ) )
243
+ );
244
+ }
245
+
246
+ /**
247
+ *
248
+ */
249
+ protected function getHumanSpamFilterItems( $fAsDefaults = false ) {
250
+ $aFilterItems = array( 'type' => 'multiple_select',
251
+ 'author_name' => _wpsf__('Author Name'),
252
+ 'author_email' => _wpsf__('Author Email'),
253
+ 'comment_content' => _wpsf__('Comment Content'),
254
+ 'url' => _wpsf__('URL'),
255
+ 'ip_address' => _wpsf__('IP Address'),
256
+ 'user_agent' => _wpsf__('Browser User Agent')
257
+ );
258
+ if ( $fAsDefaults ) {
259
+ unset($aFilterItems['type']);
260
+ return array_keys($aFilterItems);
261
+ }
262
+ return $aFilterItems;
263
  }
264
 
265
  public function updateHandler() {
src/icwp-optionshandler-email.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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_OptionsHandler_Email') ):
21
+
22
+ class ICWP_OptionsHandler_Email extends ICWP_OptionsHandler_Base_Wpsf {
23
+
24
+ const StoreName = 'email_options';
25
+
26
+ public function __construct( $insPrefix, $insVersion ) {
27
+ parent::__construct( $insPrefix, self::StoreName, $insVersion );
28
+ }
29
+
30
+ /**
31
+ * @return bool|void
32
+ */
33
+ public function defineOptions() {
34
+ $aEmail = array(
35
+ 'section_title' => _wpsf__( 'Email Options' ),
36
+ 'section_options' => array(
37
+ array(
38
+ 'block_send_email_address',
39
+ '',
40
+ '',
41
+ 'email',
42
+ _wpsf__( 'Report Email' ),
43
+ _wpsf__( 'Where to send email reports' ),
44
+ _wpsf__( 'If this is empty, it will default to the blog admin email address' )
45
+ ),
46
+ array(
47
+ 'send_email_throttle_limit',
48
+ '',
49
+ '10',
50
+ 'integer',
51
+ _wpsf__( 'Email Throttle Limit' ),
52
+ _wpsf__( 'Limit Emails Per Second' ),
53
+ _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' )
54
+ )
55
+ )
56
+ );
57
+
58
+ $this->m_aOptions = array(
59
+ $aEmail
60
+ );
61
+ }
62
+
63
+ /**
64
+ * This is the point where you would want to do any options verification
65
+ */
66
+ protected function doPrePluginOptionsSave() {
67
+ $sEmail = $this->getOpt( 'block_send_email_address');
68
+ if ( empty( $sEmail ) || !is_email( $sEmail ) ) {
69
+ $sEmail = get_option('admin_email');
70
+ }
71
+ if ( is_email( $sEmail ) ) {
72
+ $this->setOpt( 'block_send_email_address', $sEmail );
73
+ }
74
+
75
+ $sLimit = $this->getOpt( 'send_email_throttle_limit' );
76
+ if ( !is_numeric( $sLimit ) || $sLimit < 0 ) {
77
+ $sLimit = 0;
78
+ }
79
+ $this->setOpt( 'send_email_throttle_limit', $sLimit );
80
+ }
81
+
82
+ protected function updateHandler() {
83
+ $sCurrentVersion = empty( $this->m_aOptionsValues[ 'current_plugin_version' ] )? '0.0' : $this->m_aOptionsValues[ 'current_plugin_version' ];
84
+ if ( version_compare( $sCurrentVersion, '2.3.0', '<=' ) ) {
85
+ }
86
+ }
87
+
88
+ }
89
+
90
+ endif;
src/icwp-optionshandler-firewall.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -19,27 +19,31 @@ require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
19
 
20
  if ( !class_exists('ICWP_OptionsHandler_Firewall') ):
21
 
22
- class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
23
 
24
  const StoreName = 'firewall_options';
25
 
26
  public function __construct( $insPrefix, $insVersion ) {
27
  parent::__construct( $insPrefix, self::StoreName, $insVersion );
28
  }
29
-
 
 
30
  public function doPrePluginOptionsSave() {
31
 
32
- $aIpWhitelist = $this->getOpt( 'ips_blacklist' );
33
  if ( $aIpWhitelist === false ) {
34
  $aIpWhitelist = '';
35
  $this->setOpt( 'ips_whitelist', $aIpWhitelist );
36
  }
 
37
 
38
  $aIpBlacklist = $this->getOpt( 'ips_blacklist' );
39
  if ( $aIpBlacklist === false ) {
40
  $aIpBlacklist = '';
41
  $this->setOpt( 'ips_blacklist', $aIpBlacklist );
42
  }
 
43
 
44
  $aPageWhitelist = $this->getOpt( 'page_params_whitelist' );
45
  if ( $aPageWhitelist === false ) {
@@ -53,25 +57,28 @@ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
53
  $aIpWhitelist = $this->setOpt( 'block_response', $sBlockResponse );
54
  }
55
  }
56
-
57
- public function defineOptions() {
58
 
59
- $this->m_aDirectSaveOptions = array( 'whitelist_admins' );
60
-
61
- $this->m_aFirewallBase = array(
62
- 'section_title' => _wpsf__( 'Enable WordPress Firewall' ),
 
 
63
  'section_options' => array(
64
  array(
65
  'enable_firewall',
66
- '', 'N',
 
67
  'checkbox',
68
  _wpsf__( 'Enable Firewall' ),
69
  _wpsf__( 'Enable (or Disable) The WordPress Firewall Feature' ),
70
- _wpsf__( 'Regardless of any other settings, this option will turn off the Firewall feature, or enable your selected Firewall options' )
 
 
71
  )
72
  )
73
  );
74
- $this->m_aBlockTypesSection = array(
75
  'section_title' => _wpsf__( 'Firewall Blocking Options' ),
76
  'section_options' => array(
77
  array(
@@ -86,7 +93,7 @@ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
86
  array(
87
  'block_dir_traversal',
88
  '',
89
- 'N',
90
  'checkbox',
91
  _wpsf__( 'Directory Traversals' ),
92
  _wpsf__( 'Block Directory Traversals' ),
@@ -95,7 +102,7 @@ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
95
  array(
96
  'block_sql_queries',
97
  '',
98
- 'N',
99
  'checkbox',
100
  _wpsf__( 'SQL Queries' ),
101
  _wpsf__( 'Block SQL Queries' ),
@@ -113,12 +120,22 @@ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
113
  array(
114
  'block_field_truncation',
115
  '',
116
- 'N',
117
  'checkbox',
118
  _wpsf__( 'Field Truncation' ),
119
  _wpsf__( 'Block Field Truncation Attacks' ),
120
  _wpsf__( 'This will block field truncation attacks in application parameters.' )
121
  ),
 
 
 
 
 
 
 
 
 
 
122
  array(
123
  'block_exe_file_uploads',
124
  '',
@@ -140,12 +157,12 @@ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
140
  ),
141
  );
142
  $aRedirectOptions = array( 'select',
143
- array( 'redirect_die_message', 'Die With Message' ),
144
- array( 'redirect_die', 'Die' ),
145
- array( 'redirect_home', 'Redirect To Home Page' ),
146
- array( 'redirect_404', 'Return 404' ),
147
  );
148
- $this->m_aBlockSection = array(
149
  'section_title' => _wpsf__( 'Choose Firewall Block Response' ),
150
  'section_options' => array(
151
  array(
@@ -169,7 +186,7 @@ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
169
  )
170
  );
171
 
172
- $this->m_aWhitelistSection = array(
173
  'section_title' => _wpsf__( 'Whitelists - IPs, Pages, Parameters, and Users that by-pass the Firewall' ),
174
  'section_options' => array(
175
  array(
@@ -194,16 +211,25 @@ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
194
  array(
195
  'whitelist_admins',
196
  '',
197
- 'N',
198
  'checkbox',
199
- _wpsf__( 'Ignore Administrators' ),
200
  _wpsf__( 'Ignore users logged in as Administrator' ),
201
  _wpsf__( 'Authenticated administrator users will not be processed by the firewall' )
 
 
 
 
 
 
 
 
 
202
  )
203
  )
204
  );
205
 
206
- $this->m_aBlacklistSection = array(
207
  'section_title' => _wpsf__( 'Choose IP Addresses To Blacklist' ),
208
  'section_options' => array(
209
  array(
@@ -217,7 +243,7 @@ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
217
  )
218
  )
219
  );
220
- $this->m_aFirewallMiscSection = array(
221
  'section_title' => _wpsf__( 'Miscellaneous Plugin Options' ),
222
  'section_options' => array(
223
  array(
@@ -233,12 +259,12 @@ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
233
  );
234
 
235
  $this->m_aOptions = array(
236
- $this->m_aFirewallBase,
237
- $this->m_aBlockSection,
238
- $this->m_aWhitelistSection,
239
- $this->m_aBlacklistSection,
240
- $this->m_aBlockTypesSection,
241
- $this->m_aFirewallMiscSection
242
  );
243
  }
244
 
@@ -246,27 +272,37 @@ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_WPSF {
246
 
247
  $sCurrentVersion = empty( $this->m_aOptionsValues[ 'current_plugin_version' ] )? '0.0' : $this->m_aOptionsValues[ 'current_plugin_version' ];
248
  if ( version_compare( $sCurrentVersion, '1.4.0', '<' ) ) {
249
- $aSettingsKey = array(
250
- 'current_plugin_version',
251
- 'enable_firewall',
252
- 'include_cookie_checks',
253
- 'block_dir_traversal',
254
- 'block_sql_queries',
255
- 'block_wordpress_terms',
256
- 'block_field_truncation',
257
- 'block_exe_file_uploads',
258
- 'block_leading_schema',
259
- 'block_send_email',
260
- 'ips_whitelist',
261
- 'ips_blacklist',
262
- 'page_params_whitelist',
263
- 'block_response',
264
- 'enable_firewall_log',
265
- 'whitelist_admins'
266
- );
267
- $this->migrateOptions( $aSettingsKey );
268
  }//v1.4.0
269
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  }
271
 
272
  endif;
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
19
 
20
  if ( !class_exists('ICWP_OptionsHandler_Firewall') ):
21
 
22
+ class ICWP_OptionsHandler_Firewall extends ICWP_OptionsHandler_Base_Wpsf {
23
 
24
  const StoreName = 'firewall_options';
25
 
26
  public function __construct( $insPrefix, $insVersion ) {
27
  parent::__construct( $insPrefix, self::StoreName, $insVersion );
28
  }
29
+
30
+ /**
31
+ */
32
  public function doPrePluginOptionsSave() {
33
 
34
+ $aIpWhitelist = $this->getOpt( 'ips_whitelist' );
35
  if ( $aIpWhitelist === false ) {
36
  $aIpWhitelist = '';
37
  $this->setOpt( 'ips_whitelist', $aIpWhitelist );
38
  }
39
+ $this->processIpFilter( 'ips_whitelist', 'icwp_simple_firewall_whitelist_ips' );
40
 
41
  $aIpBlacklist = $this->getOpt( 'ips_blacklist' );
42
  if ( $aIpBlacklist === false ) {
43
  $aIpBlacklist = '';
44
  $this->setOpt( 'ips_blacklist', $aIpBlacklist );
45
  }
46
+ $this->processIpFilter( 'ips_blacklist', 'icwp_simple_firewall_blacklist_ips' );
47
 
48
  $aPageWhitelist = $this->getOpt( 'page_params_whitelist' );
49
  if ( $aPageWhitelist === false ) {
57
  $aIpWhitelist = $this->setOpt( 'block_response', $sBlockResponse );
58
  }
59
  }
 
 
60
 
61
+ /**
62
+ * @return bool|void
63
+ */
64
+ public function defineOptions() {
65
+ $aFirewallBase = array(
66
+ 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('WordPress Firewall') ),
67
  'section_options' => array(
68
  array(
69
  'enable_firewall',
70
+ '',
71
+ 'N',
72
  'checkbox',
73
  _wpsf__( 'Enable Firewall' ),
74
  _wpsf__( 'Enable (or Disable) The WordPress Firewall Feature' ),
75
+ sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('WordPress Firewall') ),
76
+ '<a href="http://icwp.io/43" target="_blank">'._wpsf__( 'more info' ).'</a>'
77
+ .' | <a href="http://icwp.io/wpsf01" target="_blank">'._wpsf__( 'blog' ).'</a>'
78
  )
79
  )
80
  );
81
+ $aBlockTypesSection = array(
82
  'section_title' => _wpsf__( 'Firewall Blocking Options' ),
83
  'section_options' => array(
84
  array(
93
  array(
94
  'block_dir_traversal',
95
  '',
96
+ 'Y',
97
  'checkbox',
98
  _wpsf__( 'Directory Traversals' ),
99
  _wpsf__( 'Block Directory Traversals' ),
102
  array(
103
  'block_sql_queries',
104
  '',
105
+ 'Y',
106
  'checkbox',
107
  _wpsf__( 'SQL Queries' ),
108
  _wpsf__( 'Block SQL Queries' ),
120
  array(
121
  'block_field_truncation',
122
  '',
123
+ 'Y',
124
  'checkbox',
125
  _wpsf__( 'Field Truncation' ),
126
  _wpsf__( 'Block Field Truncation Attacks' ),
127
  _wpsf__( 'This will block field truncation attacks in application parameters.' )
128
  ),
129
+ array(
130
+ 'block_php_code',
131
+ '',
132
+ 'N',
133
+ 'checkbox',
134
+ _wpsf__( 'PHP Code' ),
135
+ sprintf( _wpsf__( 'Block %s' ), _wpsf__( 'PHP Code Includes' ) ),
136
+ _wpsf__( 'This will block any data that appears to try and include PHP files.' )
137
+ .'<br />'. _wpsf__( 'Will probably block saving within the Plugin/Theme file editors.' )
138
+ ),
139
  array(
140
  'block_exe_file_uploads',
141
  '',
157
  ),
158
  );
159
  $aRedirectOptions = array( 'select',
160
+ array( 'redirect_die_message', _wpsf__( 'Die With Message' ) ),
161
+ array( 'redirect_die', _wpsf__( 'Die' ) ),
162
+ array( 'redirect_home', _wpsf__( 'Redirect To Home Page' ) ),
163
+ array( 'redirect_404', _wpsf__( 'Return 404' ) ),
164
  );
165
+ $aBlockSection = array(
166
  'section_title' => _wpsf__( 'Choose Firewall Block Response' ),
167
  'section_options' => array(
168
  array(
186
  )
187
  );
188
 
189
+ $aWhitelistSection = array(
190
  'section_title' => _wpsf__( 'Whitelists - IPs, Pages, Parameters, and Users that by-pass the Firewall' ),
191
  'section_options' => array(
192
  array(
211
  array(
212
  'whitelist_admins',
213
  '',
214
+ 'Y',
215
  'checkbox',
216
+ sprintf( _wpsf__( 'Ignore %s' ), _wpsf__( 'Administrators' ) ),
217
  _wpsf__( 'Ignore users logged in as Administrator' ),
218
  _wpsf__( 'Authenticated administrator users will not be processed by the firewall' )
219
+ ),
220
+ array(
221
+ 'ignore_search_engines',
222
+ '',
223
+ 'N',
224
+ 'checkbox',
225
+ sprintf( _wpsf__( 'Ignore %s' ), _wpsf__( 'Search Engines' ) ),
226
+ _wpsf__( 'Ignore Search Engine Bots' ),
227
+ _wpsf__( 'When selected, the firewall will try to recognise search engine spiders/bots and not apply firewall rules to them' )
228
  )
229
  )
230
  );
231
 
232
+ $aBlacklistSection = array(
233
  'section_title' => _wpsf__( 'Choose IP Addresses To Blacklist' ),
234
  'section_options' => array(
235
  array(
243
  )
244
  )
245
  );
246
+ $aMisc = array(
247
  'section_title' => _wpsf__( 'Miscellaneous Plugin Options' ),
248
  'section_options' => array(
249
  array(
259
  );
260
 
261
  $this->m_aOptions = array(
262
+ $aFirewallBase,
263
+ $aBlockSection,
264
+ $aWhitelistSection,
265
+ $aBlacklistSection,
266
+ $aBlockTypesSection,
267
+ $aMisc
268
  );
269
  }
270
 
272
 
273
  $sCurrentVersion = empty( $this->m_aOptionsValues[ 'current_plugin_version' ] )? '0.0' : $this->m_aOptionsValues[ 'current_plugin_version' ];
274
  if ( version_compare( $sCurrentVersion, '1.4.0', '<' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  }//v1.4.0
276
  }
277
+
278
+ public function addRawIpsToFirewallList( $insListName, $inaNewIps ) {
279
+ if ( empty( $inaNewIps ) ) {
280
+ return;
281
+ }
282
+
283
+ $aIplist = $this->getOpt( $insListName );
284
+ if ( empty( $aIplist ) ) {
285
+ $aIplist = array();
286
+ }
287
+ $aNewList = array();
288
+ foreach( $inaNewIps as $sAddress ) {
289
+ $aNewList[ $sAddress ] = '';
290
+ }
291
+ $this->setOpt( $insListName, ICWP_WPSF_DataProcessor::Add_New_Raw_Ips( $aIplist, $aNewList ) );
292
+ }
293
+
294
+ public function removeRawIpsFromFirewallList( $insListName, $inaRemoveIps ) {
295
+ if ( empty( $inaRemoveIps ) ) {
296
+ return;
297
+ }
298
+
299
+ $aIplist = $this->getOpt( $insListName );
300
+ if ( empty( $aIplist ) || empty( $inaRemoveIps ) ) {
301
+ return;
302
+ }
303
+ $this->setOpt( $insListName, ICWP_WPSF_DataProcessor::Remove_Raw_Ips( $aIplist, $inaRemoveIps ) );
304
+ }
305
+
306
  }
307
 
308
  endif;
src/icwp-optionshandler-lockdown.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -16,11 +16,10 @@
16
  */
17
 
18
  require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
19
- require_once( dirname(__FILE__).'/icwp-optionshandler-lockdown.php' );
20
 
21
  if ( !class_exists('ICWP_OptionsHandler_Lockdown') ):
22
 
23
- class ICWP_OptionsHandler_Lockdown extends ICWP_OptionsHandler_Base_WPSF {
24
 
25
  const StoreName = 'lockdown_options';
26
 
@@ -42,11 +41,14 @@ class ICWP_OptionsHandler_Lockdown extends ICWP_OptionsHandler_Base_WPSF {
42
  $this->setOpt( 'mask_wordpress_version', preg_replace( '/[^a-z0-9_.-]/i', '', $sCurrent ) );
43
  }
44
  }
45
-
 
 
 
46
  public function defineOptions() {
47
 
48
  $aBase = array(
49
- 'section_title' => _wpsf__( 'Enable Lockdown Feature' ),
50
  'section_options' => array(
51
  array(
52
  'enable_lockdown',
@@ -55,7 +57,8 @@ class ICWP_OptionsHandler_Lockdown extends ICWP_OptionsHandler_Base_WPSF {
55
  'checkbox',
56
  _wpsf__( 'Enable Lockdown' ),
57
  _wpsf__( 'Enable (or Disable) The Lockdown Feature' ),
58
- _wpsf__( 'Regardless of any other settings, this option will turn off the Lockdown feature, or enable your selected Lockdown options' )
 
59
  )
60
  )
61
  );
@@ -70,11 +73,34 @@ class ICWP_OptionsHandler_Lockdown extends ICWP_OptionsHandler_Base_WPSF {
70
  _wpsf__( 'Disable File Editing' ),
71
  _wpsf__( 'Disable Ability To Edit Files' ),
72
  _wpsf__( 'Removes the option to directly edit any files from within the WordPress admin area.' )
73
- .'<br />'._wpsf__( 'Equivalent to setting DISALLOW_FILE_EDIT to TRUE.' )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  )
75
  )
76
  );
77
- $aAccess = array(
78
  'section_title' => _wpsf__( 'WordPress Obscurity Options' ),
79
  'section_options' => array(
80
  array(
@@ -85,14 +111,16 @@ class ICWP_OptionsHandler_Lockdown extends ICWP_OptionsHandler_Base_WPSF {
85
  _wpsf__( 'Mask WordPress Version' ),
86
  _wpsf__( 'Prevents Public Display Of Your WordPress Version' ),
87
  _wpsf__( 'Enter how you would like your WordPress version displayed publicly. Leave blank to disable this feature.' )
88
- .'<br />'._wpsf__( 'Warning: This may interfere with WordPress plugins that rely on the $wp_version variable.' )
 
89
  )
90
  )
91
  );
92
 
93
  $this->m_aOptions = array(
94
  $aBase,
95
- $aAccess
 
96
  );
97
 
98
  if ( false && $this->getCanDoAuthSalts() ) {
@@ -115,29 +143,25 @@ class ICWP_OptionsHandler_Lockdown extends ICWP_OptionsHandler_Base_WPSF {
115
  }
116
 
117
  protected function getCanDoAuthSalts() {
118
- require_once( dirname(__FILE__).'/icwp-wpfilesystem.php' );
119
- $oWpFilesystem = new ICWP_WpFilesystem_WPSF();
120
 
121
- if ( !$oWpFilesystem->getCanWpRemoteGet() ) {
122
  return false;
123
  }
124
 
125
- if ( !$oWpFilesystem->getCanDiskWrite() ) {
126
  return false;
127
  }
128
 
129
- $sWpConfigPath = is_file( ABSPATH.'wp-config.php' )? ABSPATH.'wp-config.php' : ABSPATH.'..'.ICWP_DS.'wp-config.php';
130
 
131
- if ( !is_file( $sWpConfigPath ) ) {
132
- var_dump('no wpconfig');
133
  return false;
134
  }
135
- $mResult = $oWpFilesystem->getCanReadWriteFile( $sWpConfigPath );
136
  return !empty( $mResult );
137
  }
138
 
139
- public function updateHandler() {
140
- }
141
  }
142
 
143
  endif;
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
16
  */
17
 
18
  require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
 
19
 
20
  if ( !class_exists('ICWP_OptionsHandler_Lockdown') ):
21
 
22
+ class ICWP_OptionsHandler_Lockdown extends ICWP_OptionsHandler_Base_Wpsf {
23
 
24
  const StoreName = 'lockdown_options';
25
 
41
  $this->setOpt( 'mask_wordpress_version', preg_replace( '/[^a-z0-9_.-]/i', '', $sCurrent ) );
42
  }
43
  }
44
+
45
+ /**
46
+ * @return bool|void
47
+ */
48
  public function defineOptions() {
49
 
50
  $aBase = array(
51
+ 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('WordPress Lockdown') ),
52
  'section_options' => array(
53
  array(
54
  'enable_lockdown',
57
  'checkbox',
58
  _wpsf__( 'Enable Lockdown' ),
59
  _wpsf__( 'Enable (or Disable) The Lockdown Feature' ),
60
+ sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('WordPress Lockdown') ),
61
+ '<a href="http://icwp.io/4r" target="_blank">'._wpsf__( 'more info' ).'</a>'
62
  )
63
  )
64
  );
73
  _wpsf__( 'Disable File Editing' ),
74
  _wpsf__( 'Disable Ability To Edit Files' ),
75
  _wpsf__( 'Removes the option to directly edit any files from within the WordPress admin area.' )
76
+ .'<br />'._wpsf__( 'Equivalent to setting DISALLOW_FILE_EDIT to TRUE.' ),
77
+ '<a href="http://icwp.io/4q" target="_blank">'._wpsf__( 'more info' ).'</a>'
78
+ ),
79
+ array(
80
+ 'force_ssl_login',
81
+ '',
82
+ 'N',
83
+ 'checkbox',
84
+ _wpsf__( 'Force SSL Login' ),
85
+ _wpsf__( 'Forces Login Form To Be Submitted Over SSL' ),
86
+ _wpsf__( 'Please only enable this option if you have a valid SSL certificate installed.' )
87
+ .'<br />'._wpsf__( 'Equivalent to setting FORCE_SSL_LOGIN to TRUE.' ),
88
+ '<a href="http://icwp.io/4s" target="_blank">'._wpsf__( 'more info' ).'</a>'
89
+ ),
90
+ array(
91
+ 'force_ssl_admin',
92
+ '',
93
+ 'N',
94
+ 'checkbox',
95
+ _wpsf__( 'Force SSL Admin' ),
96
+ _wpsf__( 'Forces WordPress Admin Dashboard To Be Delivered Over SSL' ),
97
+ _wpsf__( 'Please only enable this option if you have a valid SSL certificate installed.' )
98
+ .'<br />'._wpsf__( 'Equivalent to setting FORCE_SSL_ADMIN to TRUE.' ),
99
+ '<a href="http://icwp.io/4t" target="_blank">'._wpsf__( 'more info' ).'</a>'
100
  )
101
  )
102
  );
103
+ $aObscurity = array(
104
  'section_title' => _wpsf__( 'WordPress Obscurity Options' ),
105
  'section_options' => array(
106
  array(
111
  _wpsf__( 'Mask WordPress Version' ),
112
  _wpsf__( 'Prevents Public Display Of Your WordPress Version' ),
113
  _wpsf__( 'Enter how you would like your WordPress version displayed publicly. Leave blank to disable this feature.' )
114
+ .'<br />'._wpsf__( 'Warning: This may interfere with WordPress plugins that rely on the $wp_version variable.' ),
115
+ '<a href="http://icwp.io/43" target="_blank">'._wpsf__( 'more info' ).'</a>'
116
  )
117
  )
118
  );
119
 
120
  $this->m_aOptions = array(
121
  $aBase,
122
+ $aAccess,
123
+ $aObscurity
124
  );
125
 
126
  if ( false && $this->getCanDoAuthSalts() ) {
143
  }
144
 
145
  protected function getCanDoAuthSalts() {
146
+ $oWpFs = $this->loadFileSystemProcessor();
 
147
 
148
+ if ( !$oWpFs->getCanWpRemoteGet() ) {
149
  return false;
150
  }
151
 
152
+ if ( !$oWpFs->getCanDiskWrite() ) {
153
  return false;
154
  }
155
 
156
+ $sWpConfigPath = $oWpFs->exists( ABSPATH.'wp-config.php' )? ABSPATH.'wp-config.php' : ABSPATH.'..'.ICWP_DS.'wp-config.php';
157
 
158
+ if ( !$oWpFs->exists( $sWpConfigPath ) ) {
 
159
  return false;
160
  }
161
+ $mResult = $oWpFs->getCanReadWriteFile( $sWpConfigPath );
162
  return !empty( $mResult );
163
  }
164
 
 
 
165
  }
166
 
167
  endif;
src/icwp-optionshandler-logging.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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_OptionsHandler_Logging') ):
21
+
22
+ class ICWP_OptionsHandler_Logging extends ICWP_OptionsHandler_Base_Wpsf {
23
+
24
+ const StoreName = 'logging_options';
25
+
26
+ public function __construct( $insPrefix, $insVersion ) {
27
+ parent::__construct( $insPrefix, self::StoreName, $insVersion );
28
+ }
29
+
30
+ /**
31
+ * @return bool|void
32
+ */
33
+ public function defineOptions() {
34
+ $aBase = array(
35
+ 'section_title' => _wpsf__( 'Enable Logging' ),
36
+ 'section_options' => array(
37
+ array(
38
+ 'enable_logging',
39
+ '',
40
+ 'Y',
41
+ 'checkbox',
42
+ _wpsf__( 'Enable Logging' ),
43
+ _wpsf__( 'Enable (or Disable) The Plugin Logging Feature.' ),
44
+ _wpsf__( 'Regardless of any other settings, this option will turn off the Logging system, or enable your chosen Logging options.' )
45
+ )
46
+ )
47
+ );
48
+ $this->m_aOptions = array(
49
+ $aBase
50
+ );
51
+ }
52
+
53
+ /**
54
+ * This is the point where you would want to do any options verification
55
+ */
56
+ protected function doPrePluginOptionsSave() { }
57
+ }
58
+
59
+ endif;
src/icwp-optionshandler-loginprotect.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -19,7 +19,7 @@ require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
19
 
20
  if ( !class_exists('ICWP_OptionsHandler_LoginProtect') ):
21
 
22
- class ICWP_OptionsHandler_LoginProtect extends ICWP_OptionsHandler_Base_WPSF {
23
 
24
  const StoreName = 'loginprotect_options';
25
 
@@ -27,25 +27,42 @@ class ICWP_OptionsHandler_LoginProtect extends ICWP_OptionsHandler_Base_WPSF {
27
  parent::__construct( $insPrefix, self::StoreName, $insVersion );
28
  }
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  public function defineOptions() {
31
 
32
- $this->m_aDirectSaveOptions = array();
33
-
34
- $this->m_aOptionsBase = array(
35
- 'section_title' => _wpsf__( 'Enable Login Protection' ),
36
  'section_options' => array(
37
  array(
38
  'enable_login_protect',
39
  '',
40
- 'Y',
41
  'checkbox',
42
  _wpsf__( 'Enable Login Protect' ),
43
  _wpsf__( 'Enable (or Disable) The Login Protection Feature' ),
44
- _wpsf__( 'Regardless of any other settings, this option will turn off the Login Protect feature, or enable your selected Login Protect options' )
 
 
45
  )
46
  ),
47
  );
48
- $this->m_aWhitelist = array(
49
  'section_title' => _wpsf__( 'Whitelist IPs that by-pass Login Protect' ),
50
  'section_options' => array(
51
  array(
@@ -55,21 +72,44 @@ class ICWP_OptionsHandler_LoginProtect extends ICWP_OptionsHandler_Base_WPSF {
55
  'ip_addresses',
56
  _wpsf__( 'Whitelist IP Addresses' ),
57
  _wpsf__( 'Specify IP Addresses that by-pass all Login Protect rules' ),
58
- sprintf( _wpsf__( 'Take a new line per address. Your IP address is: %s' ), '<span class="code">'.$this->getVisitorIpAddress( false ).'</span>' )
 
59
  )
60
  )
61
  );
62
- $this->m_aTwoFactorAuth = array(
 
63
  'section_title' => _wpsf__( 'Two-Factor Authentication Protection Options' ),
64
  'section_options' => array(
 
 
 
 
 
 
 
 
 
 
65
  array(
66
  'enable_two_factor_auth_by_ip',
67
  '',
68
  'N',
69
  'checkbox',
70
- _wpsf__( 'Two-Factor Authentication' ),
71
- _wpsf__( 'Two-Factor Login Authentication By IP Address' ),
72
- _wpsf__( 'All users will be required to authenticate their logins by email-based two-factor authentication when logging in from a new IP address' )
 
 
 
 
 
 
 
 
 
 
 
73
  ),
74
  array(
75
  'enable_two_factor_bypass_on_email_fail',
@@ -82,17 +122,18 @@ class ICWP_OptionsHandler_LoginProtect extends ICWP_OptionsHandler_Base_WPSF {
82
  )
83
  )
84
  );
85
- $this->m_aLoginProtect = array(
86
  'section_title' => _wpsf__( 'Login Protection Options' ),
87
  'section_options' => array(
88
  array(
89
  'login_limit_interval',
90
  '',
91
- '5',
92
  'integer',
93
- 'Login Cooldown Interval',
94
- 'Limit login attempts to every X seconds',
95
- 'WordPress will process only ONE login attempt for every number of seconds specified. Zero (0) turns this off. Suggested: 5'
 
96
  ),
97
  array(
98
  'enable_login_gasp_check',
@@ -101,12 +142,87 @@ class ICWP_OptionsHandler_LoginProtect extends ICWP_OptionsHandler_Base_WPSF {
101
  'checkbox',
102
  _wpsf__( 'G.A.S.P Protection' ),
103
  _wpsf__( 'Use G.A.S.P. Protection To Prevent Login Attempts By Bots' ),
104
- _wpsf__( 'Adds a dynamically (Javascript) generated checkbox to the login form that prevents bots using automated login techniques. Recommended: ON' )
 
 
 
 
 
 
 
 
 
 
 
105
  )
106
  )
107
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
- $this->m_aLoggingSection = array(
110
  'section_title' => _wpsf__( 'Logging Options' ),
111
  'section_options' => array(
112
  array(
@@ -122,11 +238,12 @@ class ICWP_OptionsHandler_LoginProtect extends ICWP_OptionsHandler_Base_WPSF {
122
  );
123
 
124
  $this->m_aOptions = array(
125
- $this->m_aOptionsBase,
126
- $this->m_aWhitelist,
127
- $this->m_aTwoFactorAuth,
128
- $this->m_aLoginProtect,
129
- $this->m_aLoggingSection
 
130
  );
131
  }
132
 
@@ -146,6 +263,26 @@ class ICWP_OptionsHandler_LoginProtect extends ICWP_OptionsHandler_Base_WPSF {
146
  $this->migrateOptions( $aSettingsKey );
147
  }//'1.4.0', '<'
148
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  }
150
 
151
  endif;
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
19
 
20
  if ( !class_exists('ICWP_OptionsHandler_LoginProtect') ):
21
 
22
+ class ICWP_OptionsHandler_LoginProtect extends ICWP_OptionsHandler_Base_Wpsf {
23
 
24
  const StoreName = 'loginprotect_options';
25
 
27
  parent::__construct( $insPrefix, self::StoreName, $insVersion );
28
  }
29
 
30
+ public function doPrePluginOptionsSave() {
31
+ $aIpWhitelist = $this->getOpt( 'ips_whitelist' );
32
+ if ( $aIpWhitelist === false ) {
33
+ $aIpWhitelist = '';
34
+ $this->setOpt( 'ips_whitelist', $aIpWhitelist );
35
+ }
36
+ $this->processIpFilter( 'ips_whitelist', 'icwp_simple_firewall_whitelist_ips' );
37
+
38
+ $aTwoFactorAuthRoles = $this->getOpt( 'two_factor_auth_user_roles' );
39
+ if ( empty($aTwoFactorAuthRoles) || !is_array( $aTwoFactorAuthRoles ) ) {
40
+ $this->setOpt( 'two_factor_auth_user_roles', $this->getTwoFactorUserAuthRoles( true ) );
41
+ }
42
+ }
43
+
44
+ /**
45
+ * @return bool|void
46
+ */
47
  public function defineOptions() {
48
 
49
+ $aOptionsBase = array(
50
+ 'section_title' => sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), _wpsf__('Login Protection') ),
 
 
51
  'section_options' => array(
52
  array(
53
  'enable_login_protect',
54
  '',
55
+ 'N',
56
  'checkbox',
57
  _wpsf__( 'Enable Login Protect' ),
58
  _wpsf__( 'Enable (or Disable) The Login Protection Feature' ),
59
+ sprintf( _wpsf__( 'Checking/Un-Checking this option will completely turn on/off the whole %s feature.' ), _wpsf__('Login Protection') ),
60
+ '<a href="http://icwp.io/51" target="_blank">'._wpsf__( 'more info' ).'</a>'
61
+ .' | <a href="http://icwp.io/wpsf03" target="_blank">'._wpsf__( 'blog' ).'</a>'
62
  )
63
  ),
64
  );
65
+ $aWhitelist = array(
66
  'section_title' => _wpsf__( 'Whitelist IPs that by-pass Login Protect' ),
67
  'section_options' => array(
68
  array(
72
  'ip_addresses',
73
  _wpsf__( 'Whitelist IP Addresses' ),
74
  _wpsf__( 'Specify IP Addresses that by-pass all Login Protect rules' ),
75
+ sprintf( _wpsf__( 'Take a new line per address. Your IP address is: %s' ), '<span class="code">'.$this->getVisitorIpAddress( false ).'</span>' ),
76
+ '<a href="http://icwp.io/52" target="_blank">'._wpsf__( 'more info' ).'</a>'
77
  )
78
  )
79
  );
80
+
81
+ $aTwoFactorAuth = array(
82
  'section_title' => _wpsf__( 'Two-Factor Authentication Protection Options' ),
83
  'section_options' => array(
84
+ array(
85
+ 'two_factor_auth_user_roles',
86
+ '',
87
+ $this->getTwoFactorUserAuthRoles( true ), // default is Contributors, Authors, Editors and Administrators
88
+ $this->getTwoFactorUserAuthRoles(),
89
+ _wpsf__( 'Two-Factor Auth User Roles' ),
90
+ _wpsf__( 'All User Roles Subject To Two-Factor Authentication' ),
91
+ _wpsf__( 'Select which types of users/roles will be subject to two-factor login authentication.' ),
92
+ '<a href="http://icwp.io/4v" target="_blank">'._wpsf__( 'more info' ).'</a>'
93
+ ),
94
  array(
95
  'enable_two_factor_auth_by_ip',
96
  '',
97
  'N',
98
  'checkbox',
99
+ sprintf( _wpsf__( 'Two-Factor Authentication (%s)' ), _wpsf__('IP') ),
100
+ sprintf( _wpsf__( 'Two-Factor Login Authentication By %s' ), _wpsf__('IP Address') ),
101
+ _wpsf__( 'All users will be required to authenticate their logins by email-based two-factor authentication when logging in from a new IP address' ),
102
+ '<a href="http://icwp.io/3s" target="_blank">'._wpsf__( 'more info' ).'</a>'
103
+ ),
104
+ array(
105
+ 'enable_two_factor_auth_by_cookie',
106
+ '',
107
+ 'N',
108
+ 'checkbox',
109
+ sprintf( _wpsf__( 'Two-Factor Authentication (%s)' ), _wpsf__('Cookie') ),
110
+ sprintf( _wpsf__( 'Two-Factor Login Authentication By %s' ), _wpsf__('Cookie') ),
111
+ _wpsf__( 'This will restrict all user login sessions to a single browser. Use this if your users have dynamic IP addresses.' ),
112
+ '<a href="http://icwp.io/3t" target="_blank">'._wpsf__( 'more info' ).'</a>'
113
  ),
114
  array(
115
  'enable_two_factor_bypass_on_email_fail',
122
  )
123
  )
124
  );
125
+ $aLoginProtect = array(
126
  'section_title' => _wpsf__( 'Login Protection Options' ),
127
  'section_options' => array(
128
  array(
129
  'login_limit_interval',
130
  '',
131
+ '10',
132
  'integer',
133
+ _wpsf__('Login Cooldown Interval'),
134
+ _wpsf__('Limit login attempts to every X seconds'),
135
+ _wpsf__('WordPress will process only ONE login attempt for every number of seconds specified. Zero (0) turns this off. Suggested: 5'),
136
+ '<a href="http://icwp.io/3q" target="_blank">'._wpsf__( 'more info' ).'</a>'
137
  ),
138
  array(
139
  'enable_login_gasp_check',
142
  'checkbox',
143
  _wpsf__( 'G.A.S.P Protection' ),
144
  _wpsf__( 'Use G.A.S.P. Protection To Prevent Login Attempts By Bots' ),
145
+ _wpsf__( 'Adds a dynamically (Javascript) generated checkbox to the login form that prevents bots using automated login techniques. Recommended: ON' ),
146
+ '<a href="http://icwp.io/3r" target="_blank">'._wpsf__( 'more info' ).'</a>'
147
+ ),
148
+ array(
149
+ 'enable_prevent_remote_post',
150
+ '',
151
+ 'Y',
152
+ 'checkbox',
153
+ _wpsf__( 'Prevent Remote Login' ),
154
+ _wpsf__( 'Prevents Remote Login Attempts From Other Locations' ),
155
+ _wpsf__( 'Prevents any login attempts that do not originate from your website. This prevent bots from attempting to login remotely. Recommended: ON' ),
156
+ '<a href="http://icwp.io/4n" target="_blank">'._wpsf__( 'more info' ).'</a>'
157
  )
158
  )
159
  );
160
+
161
+ $aYubikeyProtect = array(
162
+ 'section_title' => _wpsf__( 'Yubikey Authentication' ),
163
+ 'section_options' => array(
164
+ array(
165
+ 'enable_yubikey',
166
+ '',
167
+ 'N',
168
+ 'checkbox',
169
+ _wpsf__('Enable Yubikey Authentication'),
170
+ _wpsf__('Turn On / Off Yubikey Authentication On This Site'),
171
+ _wpsf__('Combined with your Yubikey API Key (below) this will form the basis of your Yubikey Authentication'),
172
+ '<a href="http://icwp.io/4f" target="_blank">'._wpsf__( 'more info' ).'</a>'
173
+ ),
174
+ array(
175
+ 'yubikey_app_id',
176
+ '',
177
+ '',
178
+ 'text',
179
+ _wpsf__('Yubikey App ID'),
180
+ _wpsf__('Your Unique Yubikey App ID'),
181
+ _wpsf__('Combined with your Yubikey API Key (below) this will form the basis of your Yubikey Authentication')
182
+ . _wpsf__( 'Please review the [more info] link on how to get your own Yubikey App ID and API Key.' ),
183
+ '<a href="http://icwp.io/4g" target="_blank">'._wpsf__( 'more info' ).'</a>'
184
+ ),
185
+ array(
186
+ 'yubikey_api_key',
187
+ '',
188
+ '',
189
+ 'text',
190
+ _wpsf__( 'Yubikey API Key' ),
191
+ _wpsf__( 'Your Unique Yubikey App API Key' ),
192
+ _wpsf__( 'Combined with your Yubikey App ID (above) this will form the basis of your Yubikey Authentication.' )
193
+ . _wpsf__( 'Please review the [more info] link on how to get your own Yubikey App ID and API Key.' ),
194
+ '<a href="http://icwp.io/4g" target="_blank">'._wpsf__( 'more info' ).'</a>'
195
+ ),
196
+ array(
197
+ 'yubikey_unique_keys',
198
+ '',
199
+ '',
200
+ 'yubikey_unique_keys',
201
+ _wpsf__( 'Yubikey Unique Keys' ),
202
+ _wpsf__( 'Permitted Username - Yubikey Pairs For This Site' ),
203
+ '<strong>'. sprintf( _wpsf__( 'Format: %s' ), 'Username,Yubikey').'</strong>'
204
+ .'<br />- '. _wpsf__( 'Provide Username<->Yubikey Pairs that are usable on this site.')
205
+ .'<br />- '. _wpsf__( 'If a Username if not assigned a Yubikey, Yubikey Authentication is OFF for that user.')
206
+ .'<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.' ),
207
+ '<a href="http://icwp.io/4h" target="_blank">'._wpsf__( 'more info' ).'</a>'
208
+ ),
209
+ /*
210
+ array(
211
+ 'enable_yubikey_only',
212
+ '',
213
+ 'N',
214
+ 'checkbox',
215
+ _wpsf__('Enable Yubikey Only'),
216
+ _wpsf__('Turn On / Off Yubikey Only Authentication'),
217
+ _wpsf__('Yubikey Only Authentication is where you can login into your WordPress site with just a Yubikey OTP.')
218
+ .'<br />- '. _wpsf__("You don't need to enter a username or a password, just a valid Yubikey OTP.")
219
+ .'<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)."),
220
+ sprintf( _wpsf__( '%smore info%s' ), '<a href="http://icwp.io/4f" target="_blank">', '</a>' )
221
+ ),*/
222
+ )
223
+ );
224
 
225
+ $aLoggingSection = array(
226
  'section_title' => _wpsf__( 'Logging Options' ),
227
  'section_options' => array(
228
  array(
238
  );
239
 
240
  $this->m_aOptions = array(
241
+ $aOptionsBase,
242
+ $aWhitelist,
243
+ $aLoginProtect,
244
+ $aTwoFactorAuth,
245
+ $aYubikeyProtect,
246
+ $aLoggingSection
247
  );
248
  }
249
 
263
  $this->migrateOptions( $aSettingsKey );
264
  }//'1.4.0', '<'
265
  }
266
+
267
+ /**
268
+ * @param boolean $fAsDefaults
269
+ * @return array
270
+ */
271
+ protected function getTwoFactorUserAuthRoles( $fAsDefaults = false ) {
272
+ $aTwoAuthRoles = array( 'type' => 'multiple_select',
273
+ 0 => _wpsf__('Subscribers'),
274
+ 1 => _wpsf__('Contributors'),
275
+ 2 => _wpsf__('Authors'),
276
+ 3 => _wpsf__('Editors'),
277
+ 8 => _wpsf__('Administrators')
278
+ );
279
+ if ( $fAsDefaults ) {
280
+ unset($aTwoAuthRoles['type']);
281
+ unset($aTwoAuthRoles[0]);
282
+ return array_keys($aTwoAuthRoles);
283
+ }
284
+ return $aTwoAuthRoles;
285
+ }
286
  }
287
 
288
  endif;
src/icwp-optionshandler-privacyprotect.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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_OptionsHandler_PrivacyProtect') ):
21
+
22
+ class ICWP_OptionsHandler_PrivacyProtect extends ICWP_OptionsHandler_Base_Wpsf {
23
+
24
+ const StoreName = 'privacyprotect_options';
25
+
26
+ public function __construct( $insPrefix, $insVersion ) {
27
+ parent::__construct( $insPrefix, self::StoreName, $insVersion );
28
+ }
29
+
30
+ public function doPrePluginOptionsSave() { }
31
+
32
+ /**
33
+ * @return bool|void
34
+ */
35
+ public function defineOptions() {
36
+
37
+ $aOptionsBase = array(
38
+ 'section_title' => _wpsf__( 'Enable Privacy Protection' ),
39
+ 'section_options' => array(
40
+ array(
41
+ 'enable_privacy_protect',
42
+ '',
43
+ 'N',
44
+ 'checkbox',
45
+ sprintf( _wpsf__( 'Enable %s' ), _wpsf__('Privacy Protection') ),
46
+ sprintf( _wpsf__( 'Enable (or Disable) The %s Feature' ), _wpsf__('Privacy Protection') ),
47
+ _wpsf__( 'Regardless of any other settings, this option will turn off the Privacy Protection feature, or enable your selected Privacy Protection options' ),
48
+ '<a href="http://icwp.io/3y" target="_blank">'._wpsf__( 'more info' ).'</a>'
49
+ )
50
+ ),
51
+ );
52
+ $aFurtherOptions = array(
53
+ 'section_title' => _wpsf__( 'Data Filtering and Logging Options' ),
54
+ 'section_options' => array(
55
+ array(
56
+ 'ignore_local_requests',
57
+ '',
58
+ 'Y',
59
+ 'checkbox',
60
+ _wpsf__( 'Ignore Local Requests' ),
61
+ _wpsf__( 'Ignore Requests This Site Makes To Itself' ),
62
+ _wpsf__( 'Does not log any requests this site makes to itself - for example the WP Cron' ),
63
+ '<a href="http://icwp.io/3y" target="_blank">'._wpsf__( 'more info' ).'</a>'
64
+ ),
65
+ array(
66
+ 'filter_wordpressorg_update_data',
67
+ '',
68
+ 'Y',
69
+ 'checkbox',
70
+ sprintf( _wpsf__( 'Enable %s' ), _wpsf__('WordPress.org Privacy') ),
71
+ _wpsf__( 'Enable Filtering Of Identifiable Data Sent To WordPress.org' ),
72
+ _wpsf__( 'With this option enabled, any identifiable information about your site will be stripped from the web requests made to WordPress.org' ),
73
+ '<a href="http://icwp.io/3y" target="_blank">'._wpsf__( 'more info' ).'</a>'
74
+ ),
75
+ array(
76
+ 'filter_site_url',
77
+ '',
78
+ 'N',
79
+ 'checkbox',
80
+ sprintf( _wpsf__( 'Enable %s' ), _wpsf__('Site URL Filter') ),
81
+ _wpsf__( 'Enable Filtering Of Your Site URL From All Web Calls' ),
82
+ _wpsf__( 'With this option enabled, all web calls made that contain your site URL will filter this URL and replace it with a random string' ),
83
+ '<a href="http://icwp.io/3y" target="_blank">'._wpsf__( 'more info' ).'</a>'
84
+ )
85
+ )
86
+ );
87
+
88
+ $this->m_aOptions = array(
89
+ $aOptionsBase,
90
+ $aFurtherOptions
91
+ );
92
+ }
93
+
94
+ public function updateHandler() {
95
+ $sCurrentVersion = empty( $this->m_aOptionsValues[ 'current_plugin_version' ] )? '0.0' : $this->m_aOptionsValues[ 'current_plugin_version' ];
96
+ }
97
+ }
98
+
99
+ endif;
src/icwp-optionshandler-wpsf.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -19,7 +19,7 @@ require_once( dirname(__FILE__).'/icwp-optionshandler-base.php' );
19
 
20
  if ( !class_exists('ICWP_OptionsHandler_Wpsf') ):
21
 
22
- class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
23
 
24
  const StoreName = 'plugin_options';
25
  const Default_AccessKeyTimeout = 30;
@@ -27,25 +27,24 @@ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
27
  public function __construct( $insPrefix, $insVersion ) {
28
  parent::__construct( $insPrefix, self::StoreName, $insVersion );
29
  }
30
-
31
- public function defineOptions() {
32
 
33
- $this->m_aIndependentOptions = array(
34
- 'firewall_processor',
35
- 'login_processor',
36
- 'comments_processor',
37
- 'lockdown_processor',
38
- 'autoupdates_processor',
39
- 'logging_processor',
40
- 'email_processor'
41
- );
42
 
43
  $aNonUiOptions = array(
 
44
  'secret_key',
45
  'feedback_admin_notice',
46
  'update_success_tracker',
47
  'capability_can_disk_write',
48
- 'capability_can_remote_get'
 
 
 
 
 
49
  );
50
  $this->mergeNonUiOptions( $aNonUiOptions );
51
 
@@ -61,8 +60,9 @@ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
61
  'checkbox',
62
  _wpsf__( 'Enable Access Key' ),
63
  _wpsf__( 'Enforce Admin Access Restriction' ),
64
- _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.' )
65
- .' '.sprintf( _wpsf__( '%smore info%s' ), '[<a href="http://icwp.io/2n" target="_blank">', '</a>]' )
 
66
  ),
67
  array(
68
  'admin_access_timeout',
@@ -72,6 +72,7 @@ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
72
  _wpsf__( 'Access Key Timeout' ),
73
  _wpsf__( 'Specify A Timeout For Plugin Admin Access' ),
74
  _wpsf__( 'This will automatically expire your WordPress Simple Firewall session. Does not apply until you enter the access key again. Default: 30 minutes.' ),
 
75
  ),
76
  array(
77
  'admin_access_key',
@@ -81,7 +82,8 @@ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
81
  _wpsf__( 'Admin Access Key' ),
82
  _wpsf__( 'Specify Your Plugin Access Key' ),
83
  _wpsf__( 'If you forget this, you could potentially lock yourself out from using this plugin.' )
84
- .'<strong>'._wpsf__( 'Leave it blank to not update it' ).'</strong>',
 
85
  )
86
  )
87
  );
@@ -89,6 +91,30 @@ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
89
 
90
  $aGeneral = array(
91
  'section_title' => _wpsf__( 'General Plugin Options' ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  'section_options' => array(
93
  array(
94
  'enable_firewall',
@@ -101,7 +127,7 @@ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
101
  array(
102
  'enable_login_protect',
103
  '',
104
- 'Y',
105
  'checkbox',
106
  _wpsf__( 'Enable Login Protect' ),
107
  _wpsf__( 'Enable (or Disable) The Login Protection Feature' ),
@@ -110,12 +136,22 @@ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
110
  array(
111
  'enable_comments_filter',
112
  '',
113
- 'Y',
114
  'checkbox',
115
  _wpsf__( 'Enable Comments Filter' ),
116
  _wpsf__( 'Enable (or Disable) The Comments Filter Feature' ),
117
  _wpsf__( 'Regardless of any other settings, this option will turn off the Comments Filter feature, or enable your selected Comments Filter options' )
118
  ),
 
 
 
 
 
 
 
 
 
 
119
  array(
120
  'enable_lockdown',
121
  '',
@@ -128,71 +164,18 @@ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
128
  array(
129
  'enable_autoupdates',
130
  '',
131
- 'N',
132
  'checkbox',
133
  _wpsf__( 'Enable Auto Updates' ),
134
  _wpsf__( 'Enable (or Disable) The Auto Updates Feature' ),
135
  _wpsf__( 'Regardless of any other settings, this option will turn off the Auto Updates feature, or enable your selected Auto Updates options' )
136
- ),
137
- /*
138
- array(
139
- 'enable_auto_plugin_upgrade',
140
- '',
141
- 'N',
142
- 'checkbox',
143
- 'Auto-Upgrade',
144
- 'When an upgrade is detected, the plugin will automatically initiate the upgrade.',
145
- 'If you prefer to manage plugin upgrades, deselect this option. Otherwise, this plugin will auto-upgrade once any available update is detected.'
146
- ),
147
- */
148
- array(
149
- 'enable_upgrade_admin_notice',
150
- '',
151
- 'Y',
152
- 'checkbox',
153
- _wpsf__( 'Plugin Upgrade Notice' ),
154
- _wpsf__( 'Display A Notice When An Upgrade Is Available' ),
155
- _wpsf__( 'Displays a notice at the top of your WordPress admin section when a plugin upgrade is available' )
156
- ),
157
- array(
158
- 'delete_on_deactivate',
159
- '',
160
- 'N',
161
- 'checkbox',
162
- _wpsf__( 'Delete Plugin Settings' ),
163
- _wpsf__( 'Delete All Plugin Settings Upon Plugin Deactivation' ),
164
- _wpsf__( 'Careful: Removes all plugin options when you deactivate the plugin' )
165
- )
166
- )
167
- );
168
-
169
- $aEmail = array(
170
- 'section_title' => _wpsf__( 'Email Options' ),
171
- 'section_options' => array(
172
- array(
173
- 'block_send_email_address',
174
- '',
175
- '',
176
- 'email',
177
- _wpsf__( 'Report Email' ),
178
- _wpsf__( 'Where to send email reports' ),
179
- _wpsf__( 'If this is empty, it will default to the blog admin email address' )
180
- ),
181
- array(
182
- 'send_email_throttle_limit',
183
- '',
184
- '10',
185
- 'integer',
186
- _wpsf__( 'Email Throttle Limit' ),
187
- _wpsf__( 'Limit Emails Per Second' ),
188
- _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' )
189
  )
190
  )
191
  );
192
 
193
  $this->m_aOptions = array(
194
  $aGeneral,
195
- $aEmail
196
  );
197
  if ( isset( $aAccessKey ) ) {
198
  array_unshift( $this->m_aOptions, $aAccessKey );
@@ -214,20 +197,13 @@ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
214
  if ( empty( $sAccessKey ) ) {
215
  $this->setOpt( 'enable_admin_access_restriction', 'N' );
216
  }
217
-
218
- $sEmail = $this->getOpt( 'block_send_email_address');
219
- if ( empty( $sEmail ) || !is_email( $sEmail ) ) {
220
- $sEmail = get_option('admin_email');
221
- }
222
- if ( is_email( $sEmail ) ) {
223
- $this->setOpt( 'block_send_email_address', $sEmail );
224
- }
225
 
226
- $sLimit = $this->getOpt( 'send_email_throttle_limit' );
227
- if ( !is_numeric( $sLimit ) || $sLimit < 0 ) {
228
- $sLimit = 0;
 
 
229
  }
230
- $this->setOpt( 'send_email_throttle_limit', $sLimit );
231
  }
232
 
233
  protected function updateHandler() {
@@ -256,13 +232,12 @@ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_WPSF {
256
  $fCanDiskWrite = $this->getOpt( 'capability_can_disk_write' );
257
 
258
  if ( $fCanDiskWrite === false || $fCanRemoteGet === false ) {
259
- require_once( dirname(__FILE__).'/icwp-wpfunctions.php' );
260
- $oWpFilesystem = new ICWP_WpFilesystem_WPSF();
261
 
262
- $fCanRemoteGet = $oWpFilesystem->getCanWpRemoteGet();
263
  $this->setOpt( 'capability_can_remote_get', $fCanRemoteGet? 'Y' : 'N' );
264
 
265
- $fCanDiskWrite = $oWpFilesystem->getCanDiskWrite();
266
  $this->setOpt( 'capability_can_disk_write', $fCanDiskWrite? 'Y' : 'N' );
267
  }
268
  }// '1.8.2', '<='
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
19
 
20
  if ( !class_exists('ICWP_OptionsHandler_Wpsf') ):
21
 
22
+ class ICWP_OptionsHandler_Wpsf extends ICWP_OptionsHandler_Base_Wpsf {
23
 
24
  const StoreName = 'plugin_options';
25
  const Default_AccessKeyTimeout = 30;
27
  public function __construct( $insPrefix, $insVersion ) {
28
  parent::__construct( $insPrefix, self::StoreName, $insVersion );
29
  }
 
 
30
 
31
+ /**
32
+ * @return bool|void
33
+ */
34
+ public function defineOptions() {
 
 
 
 
 
35
 
36
  $aNonUiOptions = array(
37
+ 'installation_time',
38
  'secret_key',
39
  'feedback_admin_notice',
40
  'update_success_tracker',
41
  'capability_can_disk_write',
42
+ 'capability_can_remote_get',
43
+ 'enable_firewall',
44
+ 'enable_login_protect',
45
+ 'enable_comments_filter',
46
+ 'enable_lockdown',
47
+ 'enable_autoupdates'
48
  );
49
  $this->mergeNonUiOptions( $aNonUiOptions );
50
 
60
  'checkbox',
61
  _wpsf__( 'Enable Access Key' ),
62
  _wpsf__( 'Enforce Admin Access Restriction' ),
63
+ _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.' ),
64
+ '<a href="http://icwp.io/40" target="_blank">'._wpsf__( 'more info' ).'</a>'
65
+ .' | <a href="http://icwp.io/wpsf02" target="_blank">'._wpsf__( 'blog' ).'</a>'
66
  ),
67
  array(
68
  'admin_access_timeout',
72
  _wpsf__( 'Access Key Timeout' ),
73
  _wpsf__( 'Specify A Timeout For Plugin Admin Access' ),
74
  _wpsf__( 'This will automatically expire your WordPress Simple Firewall session. Does not apply until you enter the access key again. Default: 30 minutes.' ),
75
+ '<a href="http://icwp.io/41" target="_blank">'._wpsf__( 'more info' ).'</a>'
76
  ),
77
  array(
78
  'admin_access_key',
82
  _wpsf__( 'Admin Access Key' ),
83
  _wpsf__( 'Specify Your Plugin Access Key' ),
84
  _wpsf__( 'If you forget this, you could potentially lock yourself out from using this plugin.' )
85
+ .' <strong>'._wpsf__( 'Leave it blank to not update it' ).'</strong>',
86
+ '<a href="http://icwp.io/42" target="_blank">'._wpsf__( 'more info' ).'</a>'
87
  )
88
  )
89
  );
91
 
92
  $aGeneral = array(
93
  'section_title' => _wpsf__( 'General Plugin Options' ),
94
+ 'section_options' => array(
95
+ array(
96
+ 'enable_upgrade_admin_notice',
97
+ '',
98
+ 'Y',
99
+ 'checkbox',
100
+ _wpsf__( 'Plugin Notices' ),
101
+ _wpsf__( 'Display Notices For Updates' ),
102
+ _wpsf__( 'Disable this option to hide certain plugin admin notices about available updates and post-update notices' )
103
+ ),
104
+ array(
105
+ 'delete_on_deactivate',
106
+ '',
107
+ 'N',
108
+ 'checkbox',
109
+ _wpsf__( 'Delete Plugin Settings' ),
110
+ _wpsf__( 'Delete All Plugin Settings Upon Plugin Deactivation' ),
111
+ _wpsf__( 'Careful: Removes all plugin options when you deactivate the plugin' )
112
+ )
113
+ )
114
+ );
115
+
116
+ $aGlobal = array(
117
+ 'section_title' => _wpsf__( 'Global Plugin Features' ),
118
  'section_options' => array(
119
  array(
120
  'enable_firewall',
127
  array(
128
  'enable_login_protect',
129
  '',
130
+ 'N',
131
  'checkbox',
132
  _wpsf__( 'Enable Login Protect' ),
133
  _wpsf__( 'Enable (or Disable) The Login Protection Feature' ),
136
  array(
137
  'enable_comments_filter',
138
  '',
139
+ 'N',
140
  'checkbox',
141
  _wpsf__( 'Enable Comments Filter' ),
142
  _wpsf__( 'Enable (or Disable) The Comments Filter Feature' ),
143
  _wpsf__( 'Regardless of any other settings, this option will turn off the Comments Filter feature, or enable your selected Comments Filter options' )
144
  ),
145
+ // array(
146
+ // 'enable_privacy_protect',
147
+ // '',
148
+ // 'N',
149
+ // 'checkbox',
150
+ // sprintf( _wpsf__( 'Enable %s' ), _wpsf__('Privacy Protection') ),
151
+ // sprintf( _wpsf__( 'Enable (or Disable) The %s Feature' ), _wpsf__('Privacy Protection') ),
152
+ // _wpsf__( 'Regardless of any other settings, this option will turn off the Privacy Protection feature, or enable your selected Privacy Protection options' ),
153
+ // '<a href="http://icwp.io/3y" target="_blank">'._wpsf__( 'more info' ).'</a>'
154
+ // ),
155
  array(
156
  'enable_lockdown',
157
  '',
164
  array(
165
  'enable_autoupdates',
166
  '',
167
+ 'Y',
168
  'checkbox',
169
  _wpsf__( 'Enable Auto Updates' ),
170
  _wpsf__( 'Enable (or Disable) The Auto Updates Feature' ),
171
  _wpsf__( 'Regardless of any other settings, this option will turn off the Auto Updates feature, or enable your selected Auto Updates options' )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  )
173
  )
174
  );
175
 
176
  $this->m_aOptions = array(
177
  $aGeneral,
178
+ // $aGlobal
179
  );
180
  if ( isset( $aAccessKey ) ) {
181
  array_unshift( $this->m_aOptions, $aAccessKey );
197
  if ( empty( $sAccessKey ) ) {
198
  $this->setOpt( 'enable_admin_access_restriction', 'N' );
199
  }
 
 
 
 
 
 
 
 
200
 
201
+ $this->setOpt( 'enable_logging', 'Y' );
202
+
203
+ $nInstalledAt = $this->getOpt( 'installation_time' );
204
+ if ( empty($nInstalledAt) || $nInstalledAt <= 0 ) {
205
+ $this->setOpt( 'installation_time', time() );
206
  }
 
207
  }
208
 
209
  protected function updateHandler() {
232
  $fCanDiskWrite = $this->getOpt( 'capability_can_disk_write' );
233
 
234
  if ( $fCanDiskWrite === false || $fCanRemoteGet === false ) {
235
+ $oWpFs = $this->loadFileSystemProcessor();
 
236
 
237
+ $fCanRemoteGet = $oWpFs->getCanWpRemoteGet();
238
  $this->setOpt( 'capability_can_remote_get', $fCanRemoteGet? 'Y' : 'N' );
239
 
240
+ $fCanDiskWrite = $oWpFs->getCanDiskWrite();
241
  $this->setOpt( 'capability_can_disk_write', $fCanDiskWrite? 'Y' : 'N' );
242
  }
243
  }// '1.8.2', '<='
src/icwp-plugins-base.php DELETED
@@ -1,692 +0,0 @@
1
- <?php
2
-
3
- if ( !defined('ICWP_DS') ) {
4
- define( 'ICWP_DS', DIRECTORY_SEPARATOR );
5
- }
6
-
7
- require_once( dirname(__FILE__).'/icwp-wpfunctions.php' );
8
-
9
- if ( !class_exists('ICWP_WPSF_Base_Plugin') ):
10
-
11
- class ICWP_WPSF_Base_Plugin {
12
-
13
- static public $VERSION;
14
-
15
- static public $PLUGIN_HUMAN_NAME;
16
- static public $PLUGIN_NAME;
17
- static public $PLUGIN_PATH;
18
- static public $PLUGIN_FILE;
19
- static public $PLUGIN_DIR;
20
- static public $PLUGIN_URL;
21
- static public $PLUGIN_BASENAME;
22
- static public $OPTION_PREFIX;
23
-
24
- const ParentTitle = 'iControlWP Plugins';
25
- const ParentName = 'Simple Firewall';
26
- const ParentPermissions = 'manage_options';
27
- const ParentMenuId = 'icwp';
28
- const VariablePrefix = 'icwp';
29
- const BaseOptionPrefix = 'icwp_';
30
-
31
- const ViewExt = '.php';
32
- const ViewDir = 'views';
33
-
34
- /**
35
- * @var boolean
36
- */
37
- protected $m_fNetworkAdminOnly = false;
38
- /**
39
- * @var boolean
40
- */
41
- protected $m_fIsMultisite;
42
-
43
- protected $m_aPluginMenu;
44
-
45
- protected $m_aAllPluginOptions;
46
-
47
- protected $m_sParentMenuIdSuffix;
48
-
49
- protected $m_fShowMarketing = '';
50
-
51
- protected $m_fDoAutoUpdateCheck = false;
52
-
53
- protected $m_fAutoPluginUpgrade = false;
54
-
55
- /**
56
- * @var ICWP_WpFunctions_WPSF
57
- */
58
- protected $m_oWpFunctions;
59
-
60
- static protected $m_aFailedUpdateOptions;
61
-
62
- public function __construct() {
63
-
64
- $this->m_fIsMultisite = function_exists( 'is_multisite' ) && is_multisite();
65
-
66
- add_action( 'plugins_loaded', array( $this, 'onWpPluginsLoaded' ) );
67
- add_action( 'init', array( $this, 'onWpInit' ), 0 );
68
- if ( $this->isValidAdminArea() ) {
69
- add_action( 'admin_init', array( $this, 'onWpAdminInit' ) );
70
- add_action( 'admin_notices', array( $this, 'onWpAdminNotices' ) );
71
- add_action( 'admin_menu', array( $this, 'onWpAdminMenu' ) );
72
- add_action( 'network_admin_menu', array( $this, 'onWpNetworkAdminMenu' ) );
73
- // add_action( 'plugin_action_links', array( $this, 'onWpPluginActionLinks' ), 10, 4 );
74
- }
75
- add_action( 'shutdown', array( $this, 'onWpShutdown' ) );
76
-
77
- /**
78
- * We make the assumption that all settings updates are successful until told otherwise
79
- * by an actual failing update_option call.
80
- */
81
- self::$m_aFailedUpdateOptions = array();
82
- $this->m_sParentMenuIdSuffix = 'base';
83
- }
84
-
85
- protected function isValidAdminArea() {
86
- if ( !$this->m_fIsMultisite && is_admin() ) {
87
- return true;
88
- }
89
- else if ( $this->m_fNetworkAdminOnly && $this->m_fIsMultisite && is_network_admin() ) {
90
- return true;
91
- }
92
- return false;
93
- }
94
-
95
- /**
96
- * @return boolean - true if plugin update is available
97
- */
98
- public function doPluginUpdateCheck() {
99
- $this->loadWpFunctions();
100
- return $this->m_oWpFunctions->getIsPluginUpdateAvailable( self::$PLUGIN_FILE );
101
- }
102
-
103
- protected function getFullParentMenuId() {
104
- return self::ParentMenuId .'-'. $this->m_sParentMenuIdSuffix;
105
- }//getFullParentMenuId
106
-
107
- protected function display( $insView, $inaData = array() ) {
108
- $sFile = dirname(__FILE__).ICWP_DS.'..'.ICWP_DS.self::ViewDir.ICWP_DS.$insView.self::ViewExt;
109
-
110
- if ( !is_file( $sFile ) ) {
111
- echo "View not found: ".$sFile;
112
- return false;
113
- }
114
-
115
- if ( count( $inaData ) > 0 ) {
116
- extract( $inaData, EXTR_PREFIX_ALL, self::VariablePrefix );
117
- }
118
-
119
- ob_start();
120
- include( $sFile );
121
- $sContents = ob_get_contents();
122
- ob_end_clean();
123
-
124
- echo $sContents;
125
- return true;
126
- }
127
-
128
- protected function getImageUrl( $insImage ) {
129
- return self::$PLUGIN_URL.'resources/images/'.$insImage;
130
- }
131
- protected function getCssUrl( $insCss ) {
132
- return self::$PLUGIN_URL.'resources/css/'.$insCss;
133
- }
134
- protected function getJsUrl( $insJs ) {
135
- return self::$PLUGIN_URL.'resources/js/'.$insJs;
136
- }
137
-
138
- protected function getSubmenuPageTitle( $insTitle ) {
139
- return self::ParentTitle.' - '.$insTitle;
140
- }
141
- protected function getSubmenuId( $insId = '' ) {
142
- $sExtension = empty($insId)? '' : '-'.$insId;
143
- return $this->getFullParentMenuId().$sExtension;
144
- }
145
-
146
- public function onWpPluginsLoaded() {
147
-
148
- if ( is_admin() ) {
149
- //Handle plugin upgrades
150
- $this->handlePluginUpgrade();
151
- }
152
-
153
- if ( $this->isIcwpPluginAdminPage() ) {
154
- //Handle form submit
155
- if ( $this->isPluginFormSubmit() && $this->handlePluginFormSubmit() ) {
156
- $this->m_oWpsfOptions->setOpt( 'feedback_admin_notice', 'Updating Settings <strong>Succeeded</strong>.' );
157
- }
158
- }
159
- }
160
-
161
- public function onWpInit() { }
162
-
163
- public function onWpAdminInit() {
164
-
165
- //Do Plugin-Specific Admin Work
166
- if ( $this->isIcwpPluginAdminPage() ) {
167
- //Links up CSS styles for the plugin itself (set the admin bootstrap CSS as a dependency also)
168
- $this->enqueuePluginAdminCss();
169
- }
170
-
171
- // Determine whether to show ads and marketing messages
172
- // Currently this is when the site uses the iControlWP service and is linked
173
- $this->isShowMarketing();
174
-
175
- }//onWpAdminInit
176
-
177
- public function onWpAdminMenu() {
178
- if ( !$this->isValidAdminArea() ) {
179
- return true;
180
- }
181
- $this->createMenu();
182
- }
183
-
184
- public function onWpNetworkAdminMenu() {
185
- if ( !$this->isValidAdminArea() ) {
186
- return true;
187
- }
188
- $this->createMenu();
189
- }
190
-
191
- protected function createMenu() {
192
-
193
- $sFullParentMenuId = $this->getFullParentMenuId();
194
- add_menu_page( self::ParentTitle, self::ParentName, self::ParentPermissions, $sFullParentMenuId, array( $this, 'onDisplayAll' ), $this->getImageUrl( 'icontrolwp_16x16.png' ) );
195
-
196
- //Create and Add the submenu items
197
- $this->createPluginSubMenuItems();
198
- if ( !empty($this->m_aPluginMenu) ) {
199
- foreach ( $this->m_aPluginMenu as $sMenuTitle => $aMenu ) {
200
- list( $sMenuItemText, $sMenuItemId, $sMenuCallBack ) = $aMenu;
201
- add_submenu_page( $sFullParentMenuId, $sMenuTitle, $sMenuItemText, self::ParentPermissions, $sMenuItemId, array( $this, $sMenuCallBack ) );
202
- }
203
- }
204
-
205
- $this->fixSubmenu();
206
- }
207
- /**
208
- * Displaying all views now goes through this central function and we work out
209
- * what to display based on the name of current hook/filter being processed.
210
- */
211
- public function onDisplayAll() {
212
- $this->onDisplayMainMenu();
213
- }
214
-
215
- protected function createPluginSubMenuItems(){
216
- /* Override to create array of sub-menu items
217
- $this->m_aPluginMenu = array(
218
- //Menu Page Title => Menu Item name, page ID (slug), callback function onLoad.
219
- $this->getSubmenuPageTitle( 'Content by Country' ) => array( 'Content by Country', $this->getSubmenuId('main'), 'onDisplayCbcMain' ),
220
- );
221
- */
222
- }//createPluginSubMenuItems
223
-
224
- protected function fixSubmenu() {
225
- global $submenu;
226
- $sFullParentMenuId = $this->getFullParentMenuId();
227
- if ( isset( $submenu[$sFullParentMenuId] ) ) {
228
- $submenu[$sFullParentMenuId][0][0] = 'Dashboard';
229
- }
230
- }
231
-
232
- /**
233
- * The callback function for the main admin menu index page
234
- */
235
- public function onDisplayMainMenu() {
236
- $aData = array(
237
- 'plugin_url' => self::$PLUGIN_URL,
238
- 'fShowAds' => $this->isShowMarketing()
239
- );
240
- $this->display( 'icwp_'.$this->m_sParentMenuIdSuffix.'_index', $aData );
241
- }
242
-
243
- protected function isShowMarketing() {
244
-
245
- if ( $this->m_fShowMarketing == 'Y' ) {
246
- return true;
247
- }
248
- elseif ( $this->m_fShowMarketing == 'N' ) {
249
- return false;
250
- }
251
-
252
- $sServiceClassName = 'Worpit_Plugin';
253
- $this->m_fShowMarketing = 'Y';
254
- if ( class_exists( 'Worpit_Plugin' ) ) {
255
- if ( method_exists( 'Worpit_Plugin', 'IsLinked' ) ) {
256
- $this->m_fShowMarketing = Worpit_Plugin::IsLinked() ? 'N' : 'Y';
257
- }
258
- elseif ( function_exists( 'get_option' )
259
- && get_option( Worpit_Plugin::$VariablePrefix.'assigned' ) == 'Y'
260
- && get_option( Worpit_Plugin::$VariablePrefix.'assigned_to' ) != '' ) {
261
-
262
- $this->m_fShowMarketing = 'N';
263
- }
264
- }
265
- return $this->m_fShowMarketing === 'N' ? false : true;
266
- }
267
-
268
- /**
269
- * The Action Links in the main plugins page. Defaults to link to the main Dashboard page
270
- *
271
- * @param $inaLinks
272
- * @param $insFile
273
- */
274
- public function onWpPluginActionLinks( $inaLinks, $insFile ) {
275
- if ( $insFile == self::$PLUGIN_BASENAME ) {
276
- $sSettingsLink = '<a href="'.admin_url( "admin.php" ).'?page='.$this->getFullParentMenuId().'">' . _wpsf__( 'Settings', 'worpit' ) . '</a>';
277
- array_unshift( $inaLinks, $sSettingsLink );
278
- }
279
- return $inaLinks;
280
- }
281
-
282
- /**
283
- * Override this method to handle all the admin notices
284
- */
285
- public function onWpAdminNotices() {
286
- // Do we have admin priviledges?
287
- if ( !current_user_can( 'manage_options' ) ) {
288
- return;
289
- }
290
-
291
- if ( $this->m_fDoAutoUpdateCheck ) {
292
- $this->adminNoticePluginUpgradeAvailable();
293
- }
294
- }
295
-
296
- /**
297
- * Hooked to 'shutdown'
298
- */
299
- public function onWpShutdown() { }
300
-
301
- /**
302
- * This is called from within onWpAdminInit. Use this solely to manage upgrades of the plugin
303
- */
304
- protected function handlePluginUpgrade() {
305
-
306
- if ( !is_admin() || !current_user_can( 'manage_options' ) ) {
307
- return;
308
- }
309
-
310
- $this->flushCaches();
311
-
312
- if ( $this->m_fAutoPluginUpgrade ) {
313
- $this->loadWpFunctions();
314
- $this->m_oWpFunctions->doPluginUpgrade( self::$PLUGIN_FILE );
315
- }
316
- }
317
-
318
- protected function isPluginFormSubmit() { }
319
-
320
- protected function handlePluginFormSubmit() { }
321
-
322
- protected function adminNoticePluginUpgradeAvailable() {
323
-
324
- // Don't show on the update page.
325
- if ( isset( $GLOBALS['pagenow'] ) && $GLOBALS['pagenow'] == 'update.php' ) {
326
- return;
327
- }
328
-
329
- if ( !isset( self::$PLUGIN_FILE ) ) {
330
- self::$PLUGIN_FILE = plugin_basename(__FILE__);
331
- }
332
- if ( !$this->doPluginUpdateCheck() ) {
333
- return;
334
- }
335
- $sNotice = $this->getAdminNoticePluginUpgradeAvailable();
336
- $this->getAdminNotice( $sNotice, 'updated', true );
337
- }
338
-
339
- /**
340
- * Override this to change the message for the particular plugin upgrade.
341
- */
342
- protected function getAdminNoticePluginUpgradeAvailable() {
343
- $sUpgradeLink = $this->m_oWpFunctions->getPluginUpgradeLink( self::$PLUGIN_FILE );
344
- $sNotice = '<p>There is an update available for the %s plugin. <a href="%s">Click to update immediately</a>.</p>';
345
- $sNotice = sprintf( $sNotice, self::$PLUGIN_HUMAN_NAME, $sUpgradeLink );
346
- return $sNotice;
347
- }
348
-
349
- protected function enqueuePluginAdminCss() {
350
- $iRand = rand();
351
- wp_register_style( 'worpit_plugin_css'.$iRand, $this->getCssUrl('icontrolwp-plugin.css'), array('worpit_bootstrap_wpadmin_css_fixes'), self::$VERSION );
352
- wp_enqueue_style( 'worpit_plugin_css'.$iRand );
353
- }//enqueuePluginAdminCss
354
-
355
- /**
356
- * Provides the basic HTML template for printing a WordPress Admin Notices
357
- *
358
- * @param $insNotice - The message to be displayed.
359
- * @param $insMessageClass - either error or updated
360
- * @param $infPrint - if true, will echo. false will return the string
361
- * @return boolean|string
362
- */
363
- protected function getAdminNotice( $insNotice = '', $insMessageClass = 'updated', $infPrint = false ) {
364
-
365
- $sFullNotice = '
366
- <div id="message" class="'.$insMessageClass.'">
367
- <style>
368
- #message form { margin: 0px; }
369
- </style>
370
- '.$insNotice.'
371
- </div>
372
- ';
373
-
374
- if ( $infPrint ) {
375
- echo $sFullNotice;
376
- return true;
377
- } else {
378
- return $sFullNotice;
379
- }
380
- }
381
-
382
- protected function redirect( $insUrl, $innTimeout = 1 ) {
383
- echo '
384
- <script type="text/javascript">
385
- function redirect() {
386
- window.location = "'.$insUrl.'";
387
- }
388
- var oTimer = setTimeout( "redirect()", "'.($innTimeout * 1000).'" );
389
- </script>';
390
- }
391
-
392
- /**
393
- * A little helper function that populates all the plugin options arrays with DB values
394
- */
395
- protected function readyAllPluginOptions() {
396
- // $this->populateAllPluginOptions();
397
- }
398
-
399
- /**
400
- * Reads the current value for ALL plugin options from the WP options db.
401
- *
402
- * Assumes the standard plugin options array structure. Over-ride to change.
403
- *
404
- * NOT automatically executed on any hooks.
405
- */
406
- protected function populateAllPluginOptions() {
407
-
408
- if ( empty($this->m_aAllPluginOptions) ) {
409
- return false;
410
- }
411
- self::PopulatePluginOptions( $this->m_aAllPluginOptions );
412
-
413
- }//populateAllPluginOptions
414
-
415
- public static function PopulatePluginOptions( &$inaAllOptions ) {
416
-
417
- if ( empty($inaAllOptions) ) {
418
- return false;
419
- }
420
- foreach ( $inaAllOptions as &$aOptionsSection ) {
421
- self::PopulatePluginOptionsSection($aOptionsSection);
422
- }
423
- }
424
-
425
- public static function PopulatePluginOptionsSection( &$inaOptionsSection ) {
426
-
427
- if ( empty($inaOptionsSection) ) {
428
- return false;
429
- }
430
- foreach ( $inaOptionsSection['section_options'] as &$aOptionParams ) {
431
-
432
- list( $sOptionKey, $sOptionCurrent, $sOptionDefault, $sOptionType ) = $aOptionParams;
433
- $mCurrentOptionVal = self::getOption( $sOptionKey );
434
- if ( $sOptionType == 'ip_addresses' ) {
435
- if ( !empty( $mCurrentOptionVal ) ) {
436
- $mCurrentOptionVal = implode( "\n", self::ConvertIpListForDisplay( $mCurrentOptionVal ) );
437
- }
438
- else {
439
- $mCurrentOptionVal = '';
440
- }
441
- }
442
- else if ( $sOptionType == 'comma_separated_lists' ) {
443
- if ( !empty( $mCurrentOptionVal ) ) {
444
- $aNewValues = array();
445
- foreach( $mCurrentOptionVal as $sPage => $aParams ) {
446
- $aNewValues[] = $sPage.', '. implode( ", ", $aParams );
447
- }
448
- $mCurrentOptionVal = implode( "\n", $aNewValues );
449
- }
450
- else {
451
- $mCurrentOptionVal = '';
452
- }
453
- }
454
- $aOptionParams[1] = ($mCurrentOptionVal == '' )? $sOptionDefault : $mCurrentOptionVal;
455
- }
456
- }
457
-
458
- public static function ConvertIpListForDisplay( $inaIpList = array() ) {
459
-
460
- $aDisplay = array();
461
- if ( empty( $inaIpList ) || empty( $inaIpList['ips'] ) ) {
462
- return $aDisplay;
463
- }
464
-
465
- foreach( $inaIpList['ips'] as $sAddress ) {
466
-
467
- $mPos = strpos( $sAddress, '-' );
468
-
469
- if ( $mPos === false || $mPos === 0 ) { //plain IP address
470
- $sDisplayText = long2ip( $sAddress );
471
- }
472
- else {
473
- list($nStart, $nEnd) = explode( '-', $sAddress );
474
- $sDisplayText = long2ip( $nStart ) .'-'. long2ip( $nEnd );
475
- }
476
- $sLabel = $inaIpList['meta'][ md5($sAddress) ];
477
- $sLabel = trim( $sLabel, '()' );
478
- $aDisplay[] = $sDisplayText . ' ('.$sLabel.')';
479
- }
480
- return $aDisplay;
481
- }
482
-
483
- /**
484
- * $sAllOptionsInput is a comma separated list of all the input keys to be processed from the $_POST
485
- */
486
- protected function updatePluginOptionsFromSubmit( $sAllOptionsInput ) {
487
-
488
- if ( empty($sAllOptionsInput) ) {
489
- return;
490
- }
491
-
492
- $aAllInputOptions = explode( ',', $sAllOptionsInput);
493
- foreach ( $aAllInputOptions as $sInputKey ) {
494
- $aInput = explode( ':', $sInputKey );
495
- list( $sOptionType, $sOptionKey ) = $aInput;
496
-
497
- $sOptionValue = $this->getAnswerFromPost( $sOptionKey );
498
- if ( is_null($sOptionValue) ) {
499
-
500
- if ( $sOptionType == 'text' || $sOptionType == 'email' ) { //if it was a text box, and it's null, don't update anything
501
- continue;
502
- } else if ( $sOptionType == 'checkbox' ) { //if it was a checkbox, and it's null, it means 'N'
503
- $sOptionValue = 'N';
504
- } else if ( $sOptionType == 'integer' ) { //if it was a integer, and it's null, it means '0'
505
- $sOptionValue = 0;
506
- }
507
- }
508
- else { //handle any pre-processing we need to.
509
-
510
- if ( $sOptionType == 'integer' ) {
511
- $sOptionValue = intval( $sOptionValue );
512
- }
513
- else if ( $sOptionType == 'ip_addresses' ) { //ip addresses are textareas, where each is separated by newline
514
-
515
- if ( !class_exists('ICWP_DataProcessor') ) {
516
- require_once ( dirname(__FILE__).'/icwp-data-processor.php' );
517
- }
518
- $oProcessor = new ICWP_DataProcessor();
519
- $sOptionValue = $oProcessor->ExtractIpAddresses( $sOptionValue );
520
- }
521
- else if ( $sOptionType == 'email' && function_exists( 'is_email' ) && !is_email( $sOptionValue ) ) {
522
- $sOptionValue = '';
523
- }
524
- else if ( $sOptionType == 'comma_separated_lists' ) {
525
- if ( !class_exists('ICWP_DataProcessor') ) {
526
- require_once ( dirname(__FILE__).'/icwp-data-processor.php' );
527
- }
528
- $oProcessor = new ICWP_DataProcessor();
529
- $sOptionValue = $oProcessor->ExtractCommaSeparatedList( $sOptionValue );
530
- }
531
- }
532
- $this->updateOption( $sOptionKey, $sOptionValue );
533
- }
534
-
535
- return true;
536
- }//updatePluginOptionsFromSubmit
537
-
538
- protected function collateAllFormInputsForAllOptions($aAllOptions, $sInputSeparator = ',') {
539
-
540
- if ( empty($aAllOptions) ) {
541
- return '';
542
- }
543
- $iCount = 0;
544
- foreach ( $aAllOptions as $aOptionsSection ) {
545
-
546
- if ( $iCount == 0 ) {
547
- $sCollated = $this->collateAllFormInputsForOptionsSection($aOptionsSection, $sInputSeparator);
548
- } else {
549
- $sCollated .= $sInputSeparator.$this->collateAllFormInputsForOptionsSection($aOptionsSection, $sInputSeparator);
550
- }
551
- $iCount++;
552
- }
553
- return $sCollated;
554
-
555
- }//collateAllFormInputsAllOptions
556
-
557
- /**
558
- * Returns a comma seperated list of all the options in a given options section.
559
- *
560
- * @param array $aOptionsSection
561
- */
562
- protected function collateAllFormInputsForOptionsSection( $aOptionsSection, $sInputSeparator = ',' ) {
563
-
564
- if ( empty($aOptionsSection) ) {
565
- return '';
566
- }
567
- $iCount = 0;
568
- foreach ( $aOptionsSection['section_options'] as $aOption ) {
569
-
570
- list($sKey, $fill1, $fill2, $sType) = $aOption;
571
-
572
- if ( $iCount == 0 ) {
573
- $sCollated = $sType.':'.$sKey;
574
- } else {
575
- $sCollated .= $sInputSeparator.$sType.':'.$sKey;
576
- }
577
- $iCount++;
578
- }
579
- return $sCollated;
580
- }
581
-
582
- protected function isIcwpPluginAdminPage() {
583
-
584
- $sSubPageNow = isset( $_GET['page'] )? $_GET['page']: '';
585
- if ( is_admin() && !empty($sSubPageNow) && (strpos( $sSubPageNow, $this->getFullParentMenuId() ) === 0 )) { //admin area, and the 'page' begins with 'worpit'
586
- return true;
587
- }
588
-
589
- return false;
590
- }//isIcwpPluginAdminPage
591
-
592
- protected function deleteAllPluginDbOptions() {
593
-
594
- if ( !current_user_can( 'manage_options' ) ) {
595
- return;
596
- }
597
-
598
- if ( empty($this->m_aAllPluginOptions) ) {
599
- return;
600
- }
601
-
602
- foreach ( $this->m_aAllPluginOptions as $aOptionsSection ) {
603
- foreach ( $aOptionsSection['section_options'] as $aOptionParams ) {
604
- if ( isset( $aOptionParams[0] ) ) {
605
- $this->deleteOption($aOptionParams[0]);
606
- }
607
- }
608
- }
609
-
610
- }//deleteAllPluginDbOptions
611
-
612
- protected function getAnswerFromPost( $insKey, $insPrefix = null ) {
613
- if ( is_null( $insPrefix ) ) {
614
- $insKey = self::getKey($insKey);
615
- }
616
- return ( isset( $_POST[$insKey] )? $_POST[$insKey]: null );
617
- }
618
-
619
- static public function getOption( $insKey, $insAddPrefix = '' ) {
620
- return get_option( self::getKey($insKey) );
621
- }
622
-
623
- static public function addOption( $insKey, $insValue ) {
624
- return add_option( self::getKey($insKey), $insValue );
625
- }
626
-
627
- static public function updateOption( $insKey, $insValue ) {
628
- if ( !is_object( $insValue ) && self::getOption( $insKey ) == $insValue ) {
629
- return true;
630
- }
631
- $fResult = update_option( self::getKey($insKey), $insValue );
632
- if ( !$fResult ) {
633
- self::$m_aFailedUpdateOptions[] = self::getKey($insKey);
634
- }
635
- }
636
-
637
- static public function deleteOption( $insKey ) {
638
- return delete_option( self::getKey($insKey) );
639
- }
640
-
641
- static public function getKey( $insKey ) {
642
- return self::$OPTION_PREFIX.$insKey;
643
- }
644
-
645
- public function onWpActivatePlugin() { }
646
- public function onWpDeactivatePlugin() { }
647
-
648
- public function onWpUninstallPlugin() {
649
-
650
- //Do we have admin priviledges?
651
- if ( current_user_can( 'manage_options' ) ) {
652
- $this->deleteAllPluginDbOptions();
653
- }
654
- }
655
-
656
- protected function loadWpFunctions() {
657
- if ( !isset( $this->m_oWpFunctions ) ) {
658
- $this->m_oWpFunctions = new ICWP_WpFunctions_WPSF();
659
- }
660
- }
661
-
662
- /**
663
- * Takes an array, an array key, and a default value. If key isn't set, sets it to default.
664
- */
665
- protected function def( &$aSrc, $insKey, $insValue = '' ) {
666
- if ( !isset( $aSrc[$insKey] ) ) {
667
- $aSrc[$insKey] = $insValue;
668
- }
669
- }
670
- /**
671
- * Takes an array, an array key and an element type. If value is empty, sets the html element
672
- * string to empty string, otherwise forms a complete html element parameter.
673
- *
674
- * E.g. noEmptyElement( aSomeArray, sSomeArrayKey, "style" )
675
- * will return String: style="aSomeArray[sSomeArrayKey]" or empty string.
676
- */
677
- protected function noEmptyElement( &$inaArgs, $insAttrKey, $insElement = '' ) {
678
- $sAttrValue = $inaArgs[$insAttrKey];
679
- $insElement = ( $insElement == '' )? $insAttrKey : $insElement;
680
- $inaArgs[$insAttrKey] = ( empty($sAttrValue) ) ? '' : ' '.$insElement.'="'.$sAttrValue.'"';
681
- }
682
-
683
- protected function flushCaches() {
684
- if (function_exists('w3tc_pgcache_flush')) {
685
- w3tc_pgcache_flush();
686
- }
687
- }
688
-
689
- }
690
-
691
- endif;
692
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/icwp-processor-autoupdates.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -17,65 +17,280 @@
17
 
18
  require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
- if ( !class_exists('ICWP_AutoUpdatesProcessor') ):
21
 
22
- class ICWP_AutoUpdatesProcessor extends ICWP_BaseProcessor_WPSF {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  /**
25
- * Resets the object values to be re-used anew
26
  */
27
- public function reset() {
28
- parent::reset();
29
  }
30
 
31
  /**
32
  */
33
- public function run() {
34
 
35
- if ( $this->m_aOptions['autoupdate_core'] == 'core_never' ) {
36
- add_filter( 'allow_minor_auto_core_updates', '__return_false' );
37
- add_filter( 'allow_major_auto_core_updates', '__return_false' );
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
39
- else if ( $this->m_aOptions['autoupdate_core'] == 'core_minor' ) {
40
- add_filter( 'allow_minor_auto_core_updates', '__return_true' );
41
- add_filter( 'allow_major_auto_core_updates', '__return_false' );
 
 
 
 
 
 
 
42
  }
43
- else if ( $this->m_aOptions['autoupdate_core'] == 'core_major' ) {
44
- add_filter( 'allow_minor_auto_core_updates', '__return_true' );
45
- add_filter( 'allow_major_auto_core_updates', '__return_true' );
46
  }
47
 
48
- $sFunction = ( $this->m_aOptions['enable_autoupdate_translations'] == 'Y' )? '__return_true' : '__return_false';
49
- add_filter( 'auto_update_translation', $sFunction );
50
-
51
- add_filter( 'auto_update_plugin', array( $this, 'autoupdate_plugins' ), 1, 2 );
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- $sFunction = ( $this->m_aOptions['enable_autoupdate_themes'] == 'Y' )? '__return_true' : '__return_false';
54
- add_filter( 'auto_update_themes', $sFunction );
 
55
 
56
- if ( $this->m_aOptions['enable_autoupdate_ignore_vcs'] == 'Y' ) {
57
- add_filter( 'automatic_updates_is_vcs_checkout', array( $this, 'disable_for_vcs'), 10, 2 );
 
58
  }
59
-
60
- if ( $this->m_aOptions['enable_autoupdate_disable_all'] == 'Y' ) {
61
- add_filter( 'automatic_updater_disabled', '__return_true' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  }
 
63
  }
64
 
65
- public function autoupdate_plugins( $infUpdate, $insPluginSlug ) {
66
-
67
- if ( strpos( $insPluginSlug, 'icwp-wpsf.php') !== false ) {
68
- return $this->m_aOptions['autoupdate_plugin_wpsf'] == 'Y';
 
 
 
 
 
 
 
69
  }
70
- if ( $this->m_aOptions['enable_autoupdate_plugins'] == 'Y' ) {
 
71
  return true;
72
  }
73
  return $infUpdate;
74
  }
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  public function disable_for_vcs( $checkout, $context ) {
77
  return false;
78
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
 
81
- endif;
 
 
 
 
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
17
 
18
  require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
+ if ( !class_exists('ICWP_AutoUpdatesProcessor_V4') ):
21
 
22
+ class ICWP_AutoUpdatesProcessor_V4 extends ICWP_BaseProcessor_V2 {
23
+
24
+ const Slug = 'autoupdates';
25
+
26
+ const FilterPriority = 1001;
27
+
28
+ protected $m_sPluginFile;
29
+
30
+ /**
31
+ * @var boolean
32
+ */
33
+ protected $m_fDoForceRunAutoUpdates = false;
34
+
35
+ public function __construct( $insOptionPrefix = '' ) {
36
+ parent::__construct( $this->constructStorageKey( $insOptionPrefix, self::Slug ) );
37
+ }
38
+
39
+ /**
40
+ * @param boolean $infDoForceRun
41
+ */
42
+ public function setForceRunAutoUpdates( $infDoForceRun ) {
43
+ $this->m_fDoForceRunAutoUpdates = $infDoForceRun;
44
+ }
45
 
46
  /**
 
47
  */
48
+ public function getForceRunAutoUpdates() {
49
+ return apply_filters( 'icwp_force_autoupdate', $this->m_fDoForceRunAutoUpdates );
50
  }
51
 
52
  /**
53
  */
54
+ public function run( $insPluginFile = '' ) {
55
 
56
+ $this->m_sPluginFile = $insPluginFile;
57
+
58
+ // When we force run we only want our filters.
59
+ if ( $this->getForceRunAutoUpdates() ) {
60
+ $aFilters = array(
61
+ 'allow_minor_auto_core_updates',
62
+ 'allow_major_auto_core_updates',
63
+ 'auto_update_translation',
64
+ 'auto_update_plugin',
65
+ 'auto_update_theme',
66
+ 'automatic_updates_is_vcs_checkout',
67
+ 'automatic_updater_disabled'
68
+ );
69
+ foreach( $aFilters as $sFilter ) {
70
+ remove_all_filters( $sFilter );
71
+ }
72
  }
73
+
74
+ add_filter( 'allow_minor_auto_core_updates', array( $this, 'autoupdate_core_minor' ), self::FilterPriority );
75
+ add_filter( 'allow_major_auto_core_updates', array( $this, 'autoupdate_core_major' ), self::FilterPriority );
76
+
77
+ add_filter( 'auto_update_translation', array( $this, 'autoupdate_translations' ), self::FilterPriority, 2 );
78
+ add_filter( 'auto_update_plugin', array( $this, 'autoupdate_plugins' ), self::FilterPriority, 2 );
79
+ add_filter( 'auto_update_theme', array( $this, 'autoupdate_themes' ), self::FilterPriority, 2 );
80
+
81
+ if ( $this->getIsOption('enable_autoupdate_ignore_vcs', 'Y') ) {
82
+ add_filter( 'automatic_updates_is_vcs_checkout', array( $this, 'disable_for_vcs' ), 10, 2 );
83
  }
84
+
85
+ if ( $this->getIsOption('enable_autoupdate_disable_all', 'Y') ) {
86
+ add_filter( 'automatic_updater_disabled', '__return_true', self::FilterPriority );
87
  }
88
 
89
+ add_filter( 'auto_core_update_send_email', array( $this, 'autoupdate_send_email' ), self::FilterPriority, 1 ); //more parameter options here for later
90
+ add_filter( 'auto_core_update_email', array( $this, 'autoupdate_email_override' ), self::FilterPriority, 1 ); //more parameter options here for later
91
+
92
+ if ( $this->getForceRunAutoUpdates() ) {
93
+ $this->force_run_autoupdates( 'update-core.php' ); //we'll redirect to the updates page for to show
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Will force-run the WordPress automatic updates process and then redirect to the updates screen.
99
+ */
100
+ public function force_run_autoupdates( $insRedirect = false ) {
101
+ $lock_name = 'auto_updater.lock'; //ref: /wp-admin/includes/class-wp-upgrader.php
102
+ delete_option( $lock_name );
103
+ if ( !defined('DOING_CRON') ) {
104
+ define( 'DOING_CRON', true ); // this prevents WP from disabling plugins pre-upgrade
105
+ }
106
 
107
+ // does the actual updating
108
+ $this->doStatIncrement( 'autoupdates.forcerun' );
109
+ wp_maybe_auto_update();
110
 
111
+ if ( !empty( $insRedirect ) ) {
112
+ wp_redirect( network_admin_url( $insRedirect ) );
113
+ exit();
114
  }
115
+ return true;
116
+ }
117
+
118
+ /**
119
+ * This is a filter method designed to say whether a major core WordPress upgrade should be permitted,
120
+ * based on the plugin settings.
121
+ *
122
+ * @param boolean $infUpdate
123
+ * @return boolean
124
+ */
125
+ public function autoupdate_core_major( $infUpdate ) {
126
+ if ( $this->getIsOption('autoupdate_core', 'core_never') ) {
127
+ $this->doStatIncrement( 'autoupdates.core.major.blocked' );
128
+ return false;
129
+ }
130
+ else if ( $this->getIsOption('autoupdate_core', 'core_major') ) {
131
+ $this->doStatIncrement( 'autoupdates.core.major.allowed' );
132
+ return true;
133
  }
134
+ return $infUpdate;
135
  }
136
 
137
+ /**
138
+ * This is a filter method designed to say whether a minor core WordPress upgrade should be permitted,
139
+ * based on the plugin settings.
140
+ *
141
+ * @param boolean $infUpdate
142
+ * @return boolean
143
+ */
144
+ public function autoupdate_core_minor( $infUpdate ) {
145
+ if ( $this->getIsOption('autoupdate_core', 'core_never') ) {
146
+ $this->doStatIncrement( 'autoupdates.core.minor.blocked' );
147
+ return false;
148
  }
149
+ else if ( $this->getIsOption('autoupdate_core', 'core_minor') ) {
150
+ $this->doStatIncrement( 'autoupdates.core.minor.allowed' );
151
  return true;
152
  }
153
  return $infUpdate;
154
  }
155
 
156
+ /**
157
+ * This is a filter method designed to say whether a WordPress translations upgrades should be permitted,
158
+ * based on the plugin settings.
159
+ *
160
+ * @param boolean $infUpdate
161
+ * @param string $insSlug
162
+ * @return boolean
163
+ */
164
+ public function autoupdate_translations( $infUpdate, $insSlug ) {
165
+ if ( $this->getIsOption('enable_autoupdate_translations', 'Y') ) {
166
+ return true;
167
+ }
168
+ return $infUpdate;
169
+ }
170
+
171
+ /**
172
+ * This is a filter method designed to say whether WordPress plugin upgrades should be permitted,
173
+ * based on the plugin settings.
174
+ *
175
+ * @param boolean $infUpdate
176
+ * @param StdClass|string $mItem
177
+ * @return boolean
178
+ */
179
+ public function autoupdate_plugins( $infUpdate, $mItem ) {
180
+
181
+ // first, is global auto updates for plugins set
182
+ if ( $this->getIsOption('enable_autoupdate_plugins', 'Y') ) {
183
+ $this->doStatIncrement( 'autoupdates.plugins.all' );
184
+ return true;
185
+ }
186
+
187
+ if ( is_object( $mItem ) && isset( $mItem->plugin ) ) { // WP 3.8.2+
188
+ $sItemFile = $mItem->plugin;
189
+ }
190
+ else if ( is_string( $mItem ) ) { // WP pre-3.8.2
191
+ $sItemFile = $mItem;
192
+ }
193
+ // at this point we don't have a slug to use so we just return the current update setting
194
+ else {
195
+ return $infUpdate;
196
+ }
197
+
198
+ if ( $sItemFile === $this->m_sPluginFile ) {
199
+ if ( $this->getIsOption('autoupdate_plugin_self', 'Y') ) {
200
+ $this->doStatIncrement( 'autoupdates.plugins.self' );
201
+ return true;
202
+ }
203
+ return false;
204
+ }
205
+
206
+ $aAutoUpdatePluginFiles = apply_filters( 'icwp_wpsf_autoupdate_plugins', array() );
207
+
208
+ if ( !empty( $aAutoUpdatePluginFiles )
209
+ && is_array($aAutoUpdatePluginFiles)
210
+ && in_array( $sItemFile, $aAutoUpdatePluginFiles ) ) {
211
+
212
+ return true;
213
+ }
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.
221
+ *
222
+ * @param boolean $infUpdate
223
+ * @param stdClass|string $mItem
224
+ * @return boolean
225
+ */
226
+ public function autoupdate_themes( $infUpdate, $mItem ) {
227
+
228
+ // first, is global auto updates for themes set
229
+ if ( $this->getIsOption('enable_autoupdate_themes', 'Y') ) {
230
+ $this->doStatIncrement( 'autoupdates.themes.all' );
231
+ return true;
232
+ }
233
+
234
+ if ( is_object( $mItem ) && isset( $mItem->theme ) ) { // WP 3.8.2+
235
+ $sItemFile = $mItem->theme;
236
+ }
237
+ else if ( is_string( $mItem ) ) { // WP pre-3.8.2
238
+ $sItemFile = $mItem;
239
+ }
240
+ // at this point we don't have a slug to use so we just return the current update setting
241
+ else {
242
+ return $infUpdate;
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
+
278
+ /**
279
+ * A filter on the target email address to which to send upgrade notification emails.
280
+ *
281
+ * @param array $aEmailParams
282
+ * @return array
283
+ */
284
+ public function autoupdate_email_override( $aEmailParams ) {
285
+ if ( !empty( $this->m_aOptions['override_email_address'] ) ) {
286
+ $aEmailParams['to'] = $this->m_aOptions['override_email_address'];
287
+ }
288
+ return $aEmailParams;
289
+ }
290
  }
291
 
292
+ endif;
293
+
294
+ if ( !class_exists('ICWP_WPSF_AutoUpdatesProcessor') ):
295
+ class ICWP_WPSF_AutoUpdatesProcessor extends ICWP_AutoUpdatesProcessor_V4 { }
296
+ endif;
src/icwp-processor-commentsfilter.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -17,56 +17,75 @@
17
 
18
  require_once( dirname(__FILE__).'/icwp-basedb-processor.php' );
19
 
20
- if ( !class_exists('ICWP_CommentsFilterProcessor') ):
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
- class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
23
-
24
- const TableName = 'comments_filter';
25
-
26
  /**
27
  * @var string
28
  */
29
  static protected $sModeFile_LoginThrottled;
30
-
31
  /**
32
  * The unique comment token assigned to this page
33
  * @var integer
34
  */
35
  protected $m_sUniqueToken;
36
-
37
  /**
38
  * The unique comment token assigned to this page
39
  * @var integer
40
  */
41
  protected $m_sUniqueFormId;
42
-
43
  /**
44
  * The length of time that must pass between a page being loaded and comment being posted.
45
  * @var integer
46
  */
47
  protected $m_nCommentCooldown;
48
-
49
  /**
50
  * The maxium length of time that comment token may last and be used.
51
  * @var integer
52
  */
53
  protected $m_nCommentTokenExpire;
54
-
 
 
55
  protected $m_nLastLoginTime;
 
 
 
56
  protected $m_sSecretKey;
57
-
 
 
58
  protected $m_sGaspKey;
59
-
60
  /**
61
- * Flag as to whether Two Factor Authentication will be by-pass when sending the verification
 
 
 
 
 
 
 
 
 
62
  * email fails.
63
  *
64
  * @var boolean
65
  */
66
  protected $m_fAllowTwoFactorByPass;
67
 
68
- public function __construct() {
69
- parent::__construct( self::TableName );
70
  $this->createTable();
71
  $this->reset();
72
  }
@@ -77,29 +96,255 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
77
  public function reset() {
78
  parent::reset();
79
  $this->m_sUniqueToken = '';
80
- $this->m_sCommentStatus = '';
 
 
81
  }
82
 
83
  /**
84
  */
85
  public function run() {
 
 
 
 
86
  // Add GASP checking to the comment form.
87
- if ( $this->m_aOptions[ 'enable_comments_gasp_protection' ] == 'Y' ) {
88
  add_action( 'comment_form', array( $this, 'printGaspFormHook_Action' ), 1 );
89
  add_action( 'comment_form', array( $this, 'printGaspFormParts_Action' ), 2 );
90
- add_filter( 'preprocess_comment', array( $this, 'doGaspCommentCheck_Filter' ), 1, 1 );
91
- add_filter( 'pre_comment_approved', array( $this, 'doGaspStatusSet_Filter' ), 1, 1 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
93
  }
 
 
 
 
 
 
 
 
94
 
95
  /**
96
  * @return void
97
  */
98
  public function printGaspFormHook_Action() {
99
 
100
- if ( !$this->getDoCommentsCheck() ) {
101
  return;
102
  }
 
103
  global $post;
104
  if ( !isset( $post ) || $post->comment_status != 'open' ) {
105
  return;
@@ -108,7 +353,7 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
108
  $this->createUniquePostCommentToken( $post->ID, $this->m_sUniqueToken );
109
 
110
  require_once( dirname(__FILE__).'/icwp-data-processor.php' );
111
- $this->m_sUniqueFormId = ICWP_DataProcessor::GenerateRandomString( rand(7, 23), true );
112
 
113
  echo $this->getGaspCommentsHookHtml();
114
  }
@@ -118,11 +363,11 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
118
  *
119
  * @return boolean
120
  */
121
- protected function getDoCommentsCheck() {
122
  if ( !is_user_logged_in() ) {
123
  return true;
124
  }
125
- else if ( $this->m_aOptions[ 'enable_comments_gasp_protection_for_logged_in' ] == 'Y' ) {
126
  return true;
127
  }
128
  return false;
@@ -132,7 +377,7 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
132
  * @return void
133
  */
134
  public function printGaspFormParts_Action() {
135
- if ( $this->getDoCommentsCheck() ) {
136
  echo $this->getGaspCommentsHtml();
137
  }
138
  }
@@ -140,7 +385,7 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
140
  /**
141
  * @return string
142
  */
143
- public function getGaspCommentsHookHtml() {
144
  $sId = $this->m_sUniqueFormId;
145
  $sReturn = '<p id="'.$sId.'"></p>'; // we use this unique <p> to hook onto using javascript
146
  $sReturn .= '<input type="hidden" id="_sugar_sweet_email" name="sugar_sweet_email" value="" />';
@@ -148,24 +393,24 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
148
  return $sReturn;
149
  }
150
 
151
- public function getGaspCommentsHtml() {
152
 
153
  $sId = $this->m_sUniqueFormId;
154
- $sConfirm = stripslashes( $this->m_aOptions[ 'custom_message_checkbox' ] );
155
- $sAlert = stripslashes( $this->m_aOptions[ 'custom_message_alert' ] );
156
- $sCommentWait = stripslashes( $this->m_aOptions[ 'custom_message_comment_wait' ] );
157
- $nCooldown = $this->m_aOptions[ 'comments_cooldown_interval' ];
158
- $nExpire = $this->m_aOptions[ 'comments_token_expire_interval' ];
159
-
160
  if ( strpos( $sCommentWait, '%s' ) !== false ) {
161
  $sCommentWait = sprintf( $sCommentWait, $nCooldown );
162
- $sJsCommentWait = str_replace( '%s', '"+nRemaining+"', $this->m_aOptions[ 'custom_message_comment_wait' ] );
163
  $sJsCommentWait = '"'.$sJsCommentWait.'"';
164
  }
165
  else {
166
- $sJsCommentWait = '"'. $this->m_aOptions[ 'custom_message_comment_wait' ].'"';
167
  }
168
- $sCommentReload = $this->m_aOptions[ 'custom_message_comment_reload' ];
169
 
170
  $sReturn = "
171
  <script type='text/javascript'>
@@ -248,40 +493,15 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
248
  ";
249
  return $sReturn;
250
  }
251
-
252
  /**
253
- * @param array $inaCommentData
254
- * @return unknown|string
 
255
  */
256
- public function doGaspCommentCheck_Filter( $inaCommentData ) {
257
-
258
- if ( !$this->getDoCommentsCheck() ) {
259
- return $inaCommentData;
260
- }
261
- if( !isset( $_POST['cb_nombre'] ) ) {
262
- $this->m_sCommentStatus = 'spam';
263
- }
264
- // we have the cb name, is it set?
265
- else if ( !isset( $_POST[ $_POST['cb_nombre'] ] ) ) {
266
- $this->m_sCommentStatus = 'spam';
267
- }
268
- // honeypot check
269
- else if ( isset( $_POST['sugar_sweet_email'] ) && $_POST['sugar_sweet_email'] !== '' ) {
270
- $this->m_sCommentStatus = 'spam';
271
- }
272
- // check the unique comment token is present
273
- else if ( !isset( $_POST['comment_token'] ) || !$this->checkCommentToken( $_POST['comment_token'], $inaCommentData['comment_post_ID'] ) ) {
274
- $this->m_sCommentStatus = 'spam';
275
- }
276
- if ( false && $this->m_sCommentStatus = 'spam' ) { //add option to die later
277
- wp_die( "Ding! Dong! The witch is dead." );
278
- }
279
- return $inaCommentData;
280
- }
281
-
282
- protected function checkCommentToken( $insCommentToken, $insPostId ) {
283
-
284
- $sToken = esc_sql( $insCommentToken ); //just incase someone try to get funky.
285
 
286
  // Try to get the database entry that corresponds to this set of data. If we get nothing, fail.
287
  $sQuery = "
@@ -296,7 +516,7 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
296
  $sQuery = sprintf( $sQuery,
297
  $this->m_sTableName,
298
  $sToken,
299
- $insPostId,
300
  $this->m_nRequestIp
301
  );
302
  $mResult = $this->selectCustomFromTable( $sQuery );
@@ -306,30 +526,48 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
306
  }
307
  else {
308
  // Only 1 chance is given per token, so we delete it
309
- $this->deleteUniquePostCommentToken( $sToken, $insPostId );
310
 
311
- // Did suficient time pass, or has it expired?
312
  $nNow = time();
313
  $aRecord = $mResult[0];
314
  $nInterval = $nNow - $aRecord['created_at'];
315
  if ( $nInterval < $this->m_aOptions[ 'comments_cooldown_interval' ]
316
- || ( $this->m_aOptions[ 'comments_token_expire_interval' ] > 0 && $nInterval > $this->m_aOptions[ 'comments_token_expire_interval' ] )
317
  ) {
318
  return false;
319
  }
320
  return true;
321
  }
322
  }
323
-
324
- public function doGaspStatusSet_Filter( $sApprovalStatus ) {
325
- if( !empty( $this->m_sCommentStatus ) ){
326
- $sApprovalStatus = $this->m_sCommentStatus;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  }
328
- return $sApprovalStatus;
329
  }
330
 
331
  public function createTable() {
332
-
333
  // Set up comments ID table
334
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
335
  `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -341,16 +579,16 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
341
  PRIMARY KEY (`id`)
342
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
343
  $sSqlTables = sprintf( $sSqlTables, $this->m_sTableName );
344
- $mResult = $this->doSql( $sSqlTables );
345
  }
346
-
347
  /**
348
- *
349
  * @param string $insUniqueToken
350
  * @param string $insPostId
 
351
  */
352
  protected function deleteUniquePostCommentToken( $insUniqueToken, $insPostId, $infSoftDelete = false ) {
353
-
354
  if ( $infSoftDelete ) {
355
  $nNow = time();
356
  $sQuery = "
@@ -361,10 +599,10 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
361
  AND `post_id` = '%s'
362
  ";
363
  $sQuery = sprintf( $sQuery,
364
- $this->m_sTableName,
365
- $nNow,
366
- $sToken,
367
- $insPostId
368
  );
369
  $this->doSql( $sQuery );
370
  }
@@ -374,14 +612,14 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
374
  $this->deleteRowsFromTable( $aWhere );
375
  }
376
  }
377
-
378
  /**
379
- *
380
  * @param string $insUniqueToken
381
  * @param string $insPostId
382
  */
383
  protected function deleteOldPostCommentTokens( $insPostId, $infSoftDelete = false ) {
384
-
385
  if ( $infSoftDelete ) {
386
  $nNow = time();
387
  $sQuery = "
@@ -400,12 +638,13 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
400
  $this->doSql( $sQuery );
401
  }
402
  else {
 
403
  $aWhere['ip_long'] = $this->m_nRequestIp;
404
  $aWhere['post_id'] = $insPostId;
405
  $this->deleteRowsFromTable( $aWhere );
406
  }
407
  }
408
-
409
  protected function createUniquePostCommentToken( $insPostId, &$outsUniqueToken = '' ) {
410
 
411
  // Now add new pending entry
@@ -425,7 +664,33 @@ class ICWP_CommentsFilterProcessor extends ICWP_BaseDbProcessor_WPSF {
425
  $sToken = uniqid( $this->m_nRequestIp.$insPostId );
426
  return md5( $sToken );
427
  }
 
 
 
 
 
 
 
 
 
 
 
428
 
 
 
 
 
 
 
 
 
 
 
 
 
429
  }
 
430
 
 
 
431
  endif;
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
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 Slug = '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
  * The unique comment token assigned to this page
40
  * @var integer
41
  */
42
  protected $m_sUniqueToken;
 
43
  /**
44
  * The unique comment token assigned to this page
45
  * @var integer
46
  */
47
  protected $m_sUniqueFormId;
 
48
  /**
49
  * The length of time that must pass between a page being loaded and comment being posted.
50
  * @var integer
51
  */
52
  protected $m_nCommentCooldown;
 
53
  /**
54
  * The maxium length of time that comment token may last and be used.
55
  * @var integer
56
  */
57
  protected $m_nCommentTokenExpire;
58
+ /**
59
+ * @var integer
60
+ */
61
  protected $m_nLastLoginTime;
62
+ /**
63
+ * @var string
64
+ */
65
  protected $m_sSecretKey;
66
+ /**
67
+ * @var string
68
+ */
69
  protected $m_sGaspKey;
 
70
  /**
71
+ * @var string
72
+ */
73
+ protected $sCommentStatus;
74
+ /**
75
+ * @var string
76
+ */
77
+ protected $sCommentStatusExplanation;
78
+
79
+ /**
80
+ * Flag as to whether Two Factor Authentication will be by-passed when sending the verification
81
  * email fails.
82
  *
83
  * @var boolean
84
  */
85
  protected $m_fAllowTwoFactorByPass;
86
 
87
+ public function __construct( $insOptionPrefix = '' ) {
88
+ parent::__construct( $this->constructStorageKey( $insOptionPrefix, self::Slug ), self::Slug );
89
  $this->createTable();
90
  $this->reset();
91
  }
96
  public function reset() {
97
  parent::reset();
98
  $this->m_sUniqueToken = '';
99
+ $this->sCommentStatus = '';
100
+ $this->sCommentStatusExplanation = '';
101
+ self::$sSpamBlacklistFile = dirname(__FILE__).ICWP_DS.'..'.ICWP_DS.'resources'.ICWP_DS.'spamblacklist.txt';
102
  }
103
 
104
  /**
105
  */
106
  public function run() {
107
+ parent::run();
108
+
109
+ $fDoSetCommentStatus = false;
110
+
111
  // Add GASP checking to the comment form.
112
+ if ( $this->getIsOption('enable_comments_gasp_protection', 'Y') ) {
113
  add_action( 'comment_form', array( $this, 'printGaspFormHook_Action' ), 1 );
114
  add_action( 'comment_form', array( $this, 'printGaspFormParts_Action' ), 2 );
115
+ }
116
+
117
+ add_filter( 'preprocess_comment', array( $this, 'doCommentPreProcess_Filter' ), 1, 1 );
118
+ add_filter( 'pre_comment_content', array( $this, 'doCommentContentPreProcess_Filter' ), 1, 1 );
119
+ add_filter( 'pre_comment_approved', array( $this, 'doSetCommentStatus_Filter' ), 1 );
120
+ }
121
+
122
+ /**
123
+ * @param array $aCommentData
124
+ * @return array
125
+ */
126
+ public function doCommentPreProcess_Filter( $aCommentData ) {
127
+
128
+ if ( !$this->getIfDoCommentsCheck() ) {
129
+ return $aCommentData;
130
+ }
131
+
132
+ $this->doGaspCommentCheck( $aCommentData['comment_post_ID'] );
133
+ $this->doBlacklistSpamCheck( $aCommentData );
134
+
135
+ // Now we check whether comment status is to completely reject and then we simply redirect to "home"
136
+ if ( $this->sCommentStatus == 'reject' ) {
137
+ $oWpFunctions = $this->loadWpFunctionsProcessor();
138
+ $oWpFunctions->redirectToHome();
139
+ }
140
+
141
+ return $aCommentData;
142
+ }
143
+
144
+ /**
145
+ * @param string $sCommentContent
146
+ * @return string
147
+ */
148
+ public function doCommentContentPreProcess_Filter( $sCommentContent ) {
149
+ // If either spam filtering process left an explanation, we add it here
150
+ if ( !empty( $this->sCommentStatusExplanation ) ) {
151
+ $sCommentContent = $this->sCommentStatusExplanation.$sCommentContent;
152
+ }
153
+ return $sCommentContent;
154
+ }
155
+
156
+ /**
157
+ * Performs the actual GASP comment checking
158
+ *
159
+ * @param $nPostId
160
+ */
161
+ protected function doGaspCommentCheck( $nPostId ) {
162
+
163
+ //Check that we haven't already marked the comment through another scan
164
+ if ( !empty( $this->sCommentStatus ) || !$this->getIsOption('enable_comments_gasp_protection', 'Y') ) {
165
+ return;
166
+ }
167
+
168
+ $fIsSpam = true;
169
+ $sExplanation = '';
170
+
171
+ // we have the cb name, is it set?
172
+ if( !isset( $_POST['cb_nombre'] ) || !isset( $_POST[ $_POST['cb_nombre'] ] ) ) {
173
+ $sExplanation = sprintf( _wpsf__('Failed GASP Bot Filter Test (%s)' ), _wpsf__('checkbox') );
174
+ $sStatKey = 'checkbox';
175
+ }
176
+ // honeypot check
177
+ else if ( isset( $_POST['sugar_sweet_email'] ) && $_POST['sugar_sweet_email'] !== '' ) {
178
+ $sExplanation = sprintf( _wpsf__('Failed GASP Bot Filter Test (%s)' ), _wpsf__('honeypot') );
179
+ $sStatKey = 'honeypot';
180
+ }
181
+ // check the unique comment token is present
182
+ else if ( !isset( $_POST['comment_token'] ) || !$this->checkCommentToken( $_POST['comment_token'], $nPostId ) ) {
183
+ $sExplanation = sprintf( _wpsf__('Failed GASP Bot Filter Test (%s)' ), _wpsf__('comment token failure') );
184
+ $sStatKey = 'token';
185
+ }
186
+ else {
187
+ $fIsSpam = false;
188
+ }
189
+
190
+ if ( $fIsSpam ) {
191
+ $this->doStatIncrement( sprintf( 'spam.gasp.%s', $sStatKey ) );
192
+ $this->sCommentStatus = $this->getOption('comments_default_action_spam_bot');
193
+ $this->setCommentStatusExplanation( $sExplanation );
194
+ }
195
+ }
196
+
197
+ /**
198
+ * @param $aCommentData
199
+ */
200
+ protected function doBlacklistSpamCheck( $aCommentData ) {
201
+ $this->loadDataProcessor();
202
+ $this->doBlacklistSpamCheck_Action(
203
+ $aCommentData['comment_author'],
204
+ $aCommentData['comment_author_email'],
205
+ $aCommentData['comment_author_url'],
206
+ $aCommentData['comment_content'],
207
+ ICWP_WPSF_DataProcessor::GetVisitorIpAddress( false ),
208
+ isset( $_SERVER['HTTP_USER_AGENT'] ) ? substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 ) : ''
209
+ );
210
+ }
211
+
212
+ /**
213
+ * Does the same as the WordPress blacklist filter, but more intelligently and with a nod towards much higher performance.
214
+ *
215
+ * It also uses defined options for which fields are checked for SPAM instead of just checking EVERYTHING!
216
+ *
217
+ * @param string $sAuthor
218
+ * @param string $sEmail
219
+ * @param string $sUrl
220
+ * @param string $sComment
221
+ * @param string $sUserIp
222
+ * @param string $sUserAgent
223
+ */
224
+ public function doBlacklistSpamCheck_Action( $sAuthor, $sEmail, $sUrl, $sComment, $sUserIp, $sUserAgent ) {
225
+
226
+ // Check that we haven't already marked the comment through another scan, say GASP
227
+ if ( !empty( $this->sCommentStatus ) || !$this->getIsOption('enable_comments_human_spam_filter', 'Y') ) {
228
+ return;
229
+ }
230
+
231
+ // read the file of spam words
232
+ $sSpamWords = $this->getSpamBlacklist();
233
+ if ( empty($sSpamWords) ) {
234
+ return;
235
+ }
236
+ $aWords = explode( "\n", $sSpamWords );
237
+
238
+ $aItemsMap = array(
239
+ 'comment_content' => $sComment,
240
+ 'url' => $sUrl,
241
+ 'author_name' => $sAuthor,
242
+ 'author_email' => $sEmail,
243
+ 'ip_address' => $sUserIp,
244
+ 'user_agent' => $sUserAgent
245
+ );
246
+ $aDesiredItemsToCheck = $this->getOption('enable_comments_human_spam_filter_items');
247
+ $aItemsToCheck = array();
248
+ foreach( $aDesiredItemsToCheck as $sKey ) {
249
+ $aItemsToCheck[$sKey] = $aItemsMap[$sKey];
250
+ }
251
+
252
+ foreach( $aItemsToCheck as $sKey => $sItem ) {
253
+ foreach ( $aWords as $sWord ) {
254
+ if ( stripos( $sItem, $sWord ) !== false ) {
255
+ //mark as spam and exit;
256
+ $this->doStatIncrement( sprintf( 'spam.human.%s', $sKey ) );
257
+ $this->doStatHumanSpamWords( $sWord );
258
+ $this->sCommentStatus = $this->getOption('comments_default_action_human_spam');
259
+ $this->setCommentStatusExplanation( sprintf( _wpsf__('Human SPAM filter found "%s" in "%s"' ), $sWord, $sKey ) );
260
+ break 2;
261
+ }
262
+ }
263
+ }
264
+ }
265
+
266
+ /**
267
+ * @param $sStatWord
268
+ */
269
+ protected function doStatHumanSpamWords( $sStatWord = '' ) {
270
+ $this->loadWpsfStatsProcessor();
271
+ if ( !empty($sStatWord) ) {
272
+ ICWP_Stats_WPSF::DoStatIncrementKeyValue( 'spam.human.words', base64_encode( $sStatWord ) );
273
+ }
274
+ }
275
+
276
+ /**
277
+ * @return null|string
278
+ */
279
+ protected function getSpamBlacklist() {
280
+ $oFs = $this->loadFileSystemProcessor();
281
+
282
+ // first, does the file exist? If not import
283
+ if ( !$oFs->exists( self::$sSpamBlacklistFile ) ) {
284
+ $this->doSpamBlacklistImport();
285
+ }
286
+ // second, if it exists and it's older than 48hrs, update
287
+ else if ( time() - $oFs->getModifiedTime( self::$sSpamBlacklistFile ) > self::TWODAYS ) {
288
+ $this->doSpamBlacklistUpdate();
289
+ }
290
+
291
+ $sList = $oFs->getFileContent( self::$sSpamBlacklistFile );
292
+ return empty($sList)? '' : $sList;
293
+ }
294
+
295
+ /**
296
+ */
297
+ protected function doSpamBlacklistUpdate() {
298
+ $oFs = $this->loadFileSystemProcessor();
299
+ $oFs->deleteFile( self::$sSpamBlacklistFile );
300
+ $this->doSpamBlacklistImport();
301
+ }
302
+
303
+ /**
304
+ */
305
+ protected function doSpamBlacklistImport() {
306
+ $oFs = $this->loadFileSystemProcessor();
307
+ if ( !$oFs->exists( self::$sSpamBlacklistFile ) ) {
308
+
309
+ $sRawList = $this->doSpamBlacklistDownload();
310
+
311
+ if ( empty($sRawList) ) {
312
+ $sList = '';
313
+ }
314
+ else {
315
+ // filter out empty lines
316
+ $aWords = explode( "\n", $sRawList );
317
+ foreach ( $aWords as $nIndex => $sWord ) {
318
+ $sWord = trim($sWord);
319
+ if ( empty($sWord) ) {
320
+ unset( $aWords[$nIndex] );
321
+ }
322
+ }
323
+ $sList = implode( "\n", $aWords );
324
+ }
325
+
326
+ // save the list to disk for the future.
327
+ $oFs->putFileContent( self::$sSpamBlacklistFile, $sList );
328
  }
329
  }
330
+
331
+ /**
332
+ * @return string
333
+ */
334
+ protected function doSpamBlacklistDownload() {
335
+ $oFs = $this->loadFileSystemProcessor();
336
+ return $oFs->getUrlContent( self::Spam_Blacklist_Source );
337
+ }
338
 
339
  /**
340
  * @return void
341
  */
342
  public function printGaspFormHook_Action() {
343
 
344
+ if ( !$this->getIfDoCommentsCheck() ) {
345
  return;
346
  }
347
+
348
  global $post;
349
  if ( !isset( $post ) || $post->comment_status != 'open' ) {
350
  return;
353
  $this->createUniquePostCommentToken( $post->ID, $this->m_sUniqueToken );
354
 
355
  require_once( dirname(__FILE__).'/icwp-data-processor.php' );
356
+ $this->m_sUniqueFormId = ICWP_WPSF_DataProcessor::GenerateRandomString( rand(7, 23), true );
357
 
358
  echo $this->getGaspCommentsHookHtml();
359
  }
363
  *
364
  * @return boolean
365
  */
366
+ protected function getIfDoCommentsCheck() {
367
  if ( !is_user_logged_in() ) {
368
  return true;
369
  }
370
+ else if ( $this->getIsOption('enable_comments_gasp_protection_for_logged_in', 'Y') ) {
371
  return true;
372
  }
373
  return false;
377
  * @return void
378
  */
379
  public function printGaspFormParts_Action() {
380
+ if ( $this->getIfDoCommentsCheck() ) {
381
  echo $this->getGaspCommentsHtml();
382
  }
383
  }
385
  /**
386
  * @return string
387
  */
388
+ protected function getGaspCommentsHookHtml() {
389
  $sId = $this->m_sUniqueFormId;
390
  $sReturn = '<p id="'.$sId.'"></p>'; // we use this unique <p> to hook onto using javascript
391
  $sReturn .= '<input type="hidden" id="_sugar_sweet_email" name="sugar_sweet_email" value="" />';
393
  return $sReturn;
394
  }
395
 
396
+ protected function getGaspCommentsHtml() {
397
 
398
  $sId = $this->m_sUniqueFormId;
399
+ $sConfirm = stripslashes( $this->getOption('custom_message_checkbox') );
400
+ $sAlert = stripslashes( $this->getOption('custom_message_alert') );
401
+ $sCommentWait = stripslashes( $this->getOption('custom_message_comment_wait') );
402
+ $nCooldown = $this->getOption('comments_cooldown_interval');
403
+ $nExpire = $this->getOption('comments_token_expire_interval');
404
+
405
  if ( strpos( $sCommentWait, '%s' ) !== false ) {
406
  $sCommentWait = sprintf( $sCommentWait, $nCooldown );
407
+ $sJsCommentWait = str_replace( '%s', '"+nRemaining+"', $this->getOption('custom_message_comment_wait') );
408
  $sJsCommentWait = '"'.$sJsCommentWait.'"';
409
  }
410
  else {
411
+ $sJsCommentWait = '"'. $this->getOption('custom_message_comment_wait').'"';
412
  }
413
+ $sCommentReload = $this->getOption('custom_message_comment_reload');
414
 
415
  $sReturn = "
416
  <script type='text/javascript'>
493
  ";
494
  return $sReturn;
495
  }
496
+
497
  /**
498
+ * @param $sCommentToken
499
+ * @param $sPostId
500
+ * @return bool
501
  */
502
+ protected function checkCommentToken( $sCommentToken, $sPostId ) {
503
+
504
+ $sToken = esc_sql( $sCommentToken ); //just in-case someones tries to get all funky up in it
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
 
506
  // Try to get the database entry that corresponds to this set of data. If we get nothing, fail.
507
  $sQuery = "
516
  $sQuery = sprintf( $sQuery,
517
  $this->m_sTableName,
518
  $sToken,
519
+ $sPostId,
520
  $this->m_nRequestIp
521
  );
522
  $mResult = $this->selectCustomFromTable( $sQuery );
526
  }
527
  else {
528
  // Only 1 chance is given per token, so we delete it
529
+ $this->deleteUniquePostCommentToken( $sToken, $sPostId );
530
 
531
+ // Did sufficient time pass, or has it expired?
532
  $nNow = time();
533
  $aRecord = $mResult[0];
534
  $nInterval = $nNow - $aRecord['created_at'];
535
  if ( $nInterval < $this->m_aOptions[ 'comments_cooldown_interval' ]
536
+ || ( $this->getOption( 'comments_token_expire_interval' ) > 0 && $nInterval > $this->getOption('comments_token_expire_interval') )
537
  ) {
538
  return false;
539
  }
540
  return true;
541
  }
542
  }
543
+
544
+ /**
545
+ * We set the final approval status of the comments if we've set it in our scans, and empties the notification email
546
+ * in case we "trash" it (since WP sends out a notification email if it's anything but SPAM)
547
+ *
548
+ * @param $sApprovalStatus
549
+ * @return string
550
+ */
551
+ public function doSetCommentStatus_Filter( $sApprovalStatus ) {
552
+ add_filter( 'comment_notification_recipients', array( $this, 'doClearCommentNotificationEmail_Filter' ), 100, 1 );
553
+ return empty( $this->sCommentStatus )? $sApprovalStatus : $this->sCommentStatus;
554
+ }
555
+
556
+ /**
557
+ * When you set a new comment as anything but 'spam' a notification email is sent to the post author.
558
+ * We suppress this for when we mark as trash by emptying the email notifications list.
559
+ *
560
+ * @param $aEmails
561
+ * @return array
562
+ */
563
+ public function doClearCommentNotificationEmail_Filter( $aEmails ) {
564
+ if ( $this->sCommentStatus == 'trash' ) {
565
+ $aEmails = array();
566
  }
567
+ return $aEmails;
568
  }
569
 
570
  public function createTable() {
 
571
  // Set up comments ID table
572
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
573
  `id` int(11) NOT NULL AUTO_INCREMENT,
579
  PRIMARY KEY (`id`)
580
  ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
581
  $sSqlTables = sprintf( $sSqlTables, $this->m_sTableName );
582
+ return $this->doSql( $sSqlTables );
583
  }
584
+
585
  /**
 
586
  * @param string $insUniqueToken
587
  * @param string $insPostId
588
+ * @param boolean $infSoftDelete
589
  */
590
  protected function deleteUniquePostCommentToken( $insUniqueToken, $insPostId, $infSoftDelete = false ) {
591
+
592
  if ( $infSoftDelete ) {
593
  $nNow = time();
594
  $sQuery = "
599
  AND `post_id` = '%s'
600
  ";
601
  $sQuery = sprintf( $sQuery,
602
+ $this->m_sTableName,
603
+ $nNow,
604
+ $insUniqueToken,
605
+ $insPostId
606
  );
607
  $this->doSql( $sQuery );
608
  }
612
  $this->deleteRowsFromTable( $aWhere );
613
  }
614
  }
615
+
616
  /**
617
+ *
618
  * @param string $insUniqueToken
619
  * @param string $insPostId
620
  */
621
  protected function deleteOldPostCommentTokens( $insPostId, $infSoftDelete = false ) {
622
+
623
  if ( $infSoftDelete ) {
624
  $nNow = time();
625
  $sQuery = "
638
  $this->doSql( $sQuery );
639
  }
640
  else {
641
+ $aWhere = array();
642
  $aWhere['ip_long'] = $this->m_nRequestIp;
643
  $aWhere['post_id'] = $insPostId;
644
  $this->deleteRowsFromTable( $aWhere );
645
  }
646
  }
647
+
648
  protected function createUniquePostCommentToken( $insPostId, &$outsUniqueToken = '' ) {
649
 
650
  // Now add new pending entry
664
  $sToken = uniqid( $this->m_nRequestIp.$insPostId );
665
  return md5( $sToken );
666
  }
667
+
668
+ /**
669
+ * @param $sExplanation
670
+ */
671
+ protected function setCommentStatusExplanation( $sExplanation ) {
672
+ $this->sCommentStatusExplanation =
673
+ '[* '.sprintf( _wpsf__('WordPress Simple Firewall plugin marked this comment as "%s" because: %s.'),
674
+ $this->sCommentStatus,
675
+ $sExplanation
676
+ )." *]\n";
677
+ }
678
 
679
+ /**
680
+ * This is hooked into a cron in the base class and overrides the parent method.
681
+ *
682
+ * It'll delete everything older than 24hrs.
683
+ */
684
+ public function cleanupDatabase() {
685
+ if ( !$this->getTableExists() ) {
686
+ return;
687
+ }
688
+ $nTimeStamp = time() - DAY_IN_SECONDS;
689
+ $this->deleteAllRowsOlderThan( $nTimeStamp );
690
+ }
691
  }
692
+ endif;
693
 
694
+ if ( !class_exists('ICWP_WPSF_CommentsFilterProcessor') ):
695
+ class ICWP_WPSF_CommentsFilterProcessor extends ICWP_CommentsFilterProcessor_V2 { }
696
  endif;
src/icwp-processor-email.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -17,9 +17,11 @@
17
 
18
  require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
- if ( !class_exists('ICWP_EmailProcessor') ):
21
 
22
- class ICWP_EmailProcessor extends ICWP_BaseProcessor_WPSF {
 
 
23
 
24
  protected $m_sRecipientAddress;
25
  protected $m_sSiteName;
@@ -31,7 +33,7 @@ class ICWP_EmailProcessor extends ICWP_BaseProcessor_WPSF {
31
  /**
32
  * @var int
33
  */
34
- static protected $nThrottleInterval = 20;
35
  /**
36
  * @var int
37
  */
@@ -48,6 +50,10 @@ class ICWP_EmailProcessor extends ICWP_BaseProcessor_WPSF {
48
  * @var boolean
49
  */
50
  protected $m_fEmailIsThrottled;
 
 
 
 
51
 
52
  public function reset() {
53
  parent::reset();
@@ -65,17 +71,19 @@ class ICWP_EmailProcessor extends ICWP_BaseProcessor_WPSF {
65
  $aHeaders = array(
66
  'MIME-Version: 1.0',
67
  'Content-type: text/plain;',
68
- sprintf( 'From: %s, Simple Firewall Plugin <%s>', $this->m_sSiteName, $insEmailAddress ),
69
  sprintf( "Subject: %s", $insEmailSubject ),
70
  'X-Mailer: PHP/'.phpversion()
71
  );
72
 
73
  $this->updateEmailThrottle();
74
- // We appear to have "succeeded" if the throttle is applied.
75
  if ( $this->m_fEmailIsThrottled ) {
76
  return true;
77
  }
78
- return wp_mail( $insEmailAddress, $insEmailSubject, implode( "\r\n", $inaMessage ), implode( "\r\n", $aHeaders ) );
 
 
79
  }
80
 
81
  /**
@@ -85,10 +93,7 @@ class ICWP_EmailProcessor extends ICWP_BaseProcessor_WPSF {
85
  * @param array $inaMessage
86
  */
87
  public function sendEmail( $insEmailSubject, $inaMessage ) {
88
- if ( !isset( $this->m_sRecipientAddress ) ) {
89
- return false;
90
- }
91
- return $this->sendEmailTo( $this->m_sRecipientAddress, $insEmailSubject, $inaMessage );
92
  }
93
 
94
  /**
@@ -102,7 +107,7 @@ class ICWP_EmailProcessor extends ICWP_BaseProcessor_WPSF {
102
  protected function updateEmailThrottle() {
103
 
104
  // Throttling Is Effectively Off
105
- if ( $this->m_nEmailThrottleLimit <= 0 ) {
106
  $this->setThrottledFile( false );
107
  return $this->m_fEmailIsThrottled;
108
  }
@@ -132,7 +137,7 @@ class ICWP_EmailProcessor extends ICWP_BaseProcessor_WPSF {
132
  $this->m_nEmailThrottleCount = 1; //we set to 1 assuming that this was called because we're about to send, or have just sent, an email.
133
  $this->setThrottledFile( false );
134
  }
135
- else if ( is_file( self::$sModeFile_EmailThrottled ) || ( $this->m_nEmailThrottleCount >= $this->m_nEmailThrottleLimit ) ) {
136
  $this->setThrottledFile( true );
137
  }
138
  else {
@@ -147,7 +152,7 @@ class ICWP_EmailProcessor extends ICWP_BaseProcessor_WPSF {
147
  if ( $infOn && !is_file( self::$sModeFile_EmailThrottled ) && function_exists('touch') ) {
148
  @touch( self::$sModeFile_EmailThrottled );
149
  }
150
- else if ( is_file(self::$sModeFile_EmailThrottled) ) {
151
  @unlink( self::$sModeFile_EmailThrottled );
152
  }
153
  }
@@ -156,13 +161,34 @@ class ICWP_EmailProcessor extends ICWP_BaseProcessor_WPSF {
156
  $this->m_sRecipientAddress = $insEmailAddress;
157
  }
158
 
 
 
 
 
 
 
 
159
  public function setSiteName( $insName ) {
160
  $this->m_sSiteName = $insName;
161
  }
162
 
163
- public function setThrottleLimit( $innLimit ) {
164
- $this->m_nEmailThrottleLimit = $innLimit;
 
 
 
 
 
 
 
 
 
 
165
  }
166
  }
167
 
 
 
 
 
168
  endif;
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
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
 
26
  protected $m_sRecipientAddress;
27
  protected $m_sSiteName;
33
  /**
34
  * @var int
35
  */
36
+ static protected $nThrottleInterval = 1;
37
  /**
38
  * @var int
39
  */
50
  * @var boolean
51
  */
52
  protected $m_fEmailIsThrottled;
53
+
54
+ public function __construct( $insOptionPrefix = '' ) {
55
+ parent::__construct( $this->constructStorageKey( $insOptionPrefix, self::Slug ) );
56
+ }
57
 
58
  public function reset() {
59
  parent::reset();
71
  $aHeaders = array(
72
  'MIME-Version: 1.0',
73
  'Content-type: text/plain;',
74
+ sprintf( 'From: %s, Simple Firewall Plugin <%s>', $this->getSiteName(), $insEmailAddress ),
75
  sprintf( "Subject: %s", $insEmailSubject ),
76
  'X-Mailer: PHP/'.phpversion()
77
  );
78
 
79
  $this->updateEmailThrottle();
80
+ // We make it appear to have "succeeded" if the throttle is applied.
81
  if ( $this->m_fEmailIsThrottled ) {
82
  return true;
83
  }
84
+ $fSuccess = wp_mail( $insEmailAddress, $insEmailSubject, implode( "\r\n", $inaMessage ), implode( "\r\n", $aHeaders ) );
85
+ $this->store();
86
+ return $fSuccess;
87
  }
88
 
89
  /**
93
  * @param array $inaMessage
94
  */
95
  public function sendEmail( $insEmailSubject, $inaMessage ) {
96
+ return $this->sendEmailTo( $this->getDefaultRecipientAddress(), $insEmailSubject, $inaMessage );
 
 
 
97
  }
98
 
99
  /**
107
  protected function updateEmailThrottle() {
108
 
109
  // Throttling Is Effectively Off
110
+ if ( $this->getThrottleLimit() <= 0 ) {
111
  $this->setThrottledFile( false );
112
  return $this->m_fEmailIsThrottled;
113
  }
137
  $this->m_nEmailThrottleCount = 1; //we set to 1 assuming that this was called because we're about to send, or have just sent, an email.
138
  $this->setThrottledFile( false );
139
  }
140
+ else if ( is_file( self::$sModeFile_EmailThrottled ) || ( $this->m_nEmailThrottleCount >= $this->getThrottleLimit() ) ) {
141
  $this->setThrottledFile( true );
142
  }
143
  else {
152
  if ( $infOn && !is_file( self::$sModeFile_EmailThrottled ) && function_exists('touch') ) {
153
  @touch( self::$sModeFile_EmailThrottled );
154
  }
155
+ else if ( !$infOn && is_file(self::$sModeFile_EmailThrottled) ) {
156
  @unlink( self::$sModeFile_EmailThrottled );
157
  }
158
  }
161
  $this->m_sRecipientAddress = $insEmailAddress;
162
  }
163
 
164
+ public function getDefaultRecipientAddress() {
165
+ if ( empty( $this->m_sRecipientAddress ) ) {
166
+ $this->m_sRecipientAddress = $this->m_aOptions[ 'block_send_email_address' ];
167
+ }
168
+ return $this->m_sRecipientAddress;
169
+ }
170
+
171
  public function setSiteName( $insName ) {
172
  $this->m_sSiteName = $insName;
173
  }
174
 
175
+ public function getSiteName() {
176
+ if ( empty( $this->m_sSiteName ) ) {
177
+ $this->m_sSiteName = function_exists( 'get_bloginfo' )? get_bloginfo('name') : 'WordPress Site';
178
+ }
179
+ return $this->m_sSiteName;
180
+ }
181
+
182
+ public function getThrottleLimit() {
183
+ if ( empty( $this->m_nEmailThrottleLimit ) ) {
184
+ $this->m_nEmailThrottleLimit = $this->m_aOptions[ 'send_email_throttle_limit' ];
185
+ }
186
+ return $this->m_nEmailThrottleLimit;
187
  }
188
  }
189
 
190
+ endif;
191
+
192
+ if ( !class_exists('ICWP_WPSF_EmailProcessor') ):
193
+ class ICWP_WPSF_EmailProcessor extends ICWP_EmailProcessor_V1 { }
194
  endif;
src/icwp-processor-firewall.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -17,9 +17,11 @@
17
 
18
  require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
- if ( !class_exists('ICWP_FirewallProcessor') ):
21
 
22
- class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
 
 
23
 
24
  protected $m_nRequestTimestamp;
25
 
@@ -34,6 +36,11 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
34
  private $m_nLoopProtect;
35
  private $m_sFirewallMessage;
36
 
 
 
 
 
 
37
  /**
38
  * @var string
39
  */
@@ -63,15 +70,15 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
63
  */
64
  protected $m_aPageParamValues;
65
 
66
- public function __construct() {
67
- parent::__construct();
68
 
69
  $sMessage = "You were blocked by the %sWordPress Simple Firewall%s.";
70
  $this->m_sFirewallMessage = sprintf( $sMessage, '<a href="http://wordpress.org/plugins/wp-simple-firewall/" target="_blank">', '</a>');
71
  }
72
 
73
  /**
74
- * @see ICWP_BaseProcessor_WPSF::setOptions()
75
  */
76
  public function setOptions( &$inaOptions ) {
77
  parent::setOptions( $inaOptions );
@@ -83,16 +90,17 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
83
  'block_sql_queries',
84
  'block_wordpress_terms',
85
  'block_field_truncation',
 
86
  'block_exe_file_uploads',
87
  'block_leading_schema'
88
  );
89
  $this->m_aBlockSettings = array();
90
  foreach( $aSettingSlugs as $sSettingKey ) {
91
- $this->m_aBlockSettings[ $sSettingKey ] = $this->m_aOptions[$sSettingKey] == 'Y';
92
  }
93
 
94
  $this->m_aCustomWhitelistPageParams = is_array( $this->m_aOptions[ 'page_params_whitelist' ] )? $this->m_aOptions[ 'page_params_whitelist' ] : array();
95
- $this->setLogging( $this->m_aOptions[ 'enable_firewall_log' ] == 'Y' );
96
  }
97
 
98
  /**
@@ -109,13 +117,14 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
109
  parent::reset();
110
  $this->m_nRequestTimestamp = time();
111
  $this->m_nLoopProtect = 0;
 
112
  }
113
 
114
  /**
115
  * Should return false when logging is disabled.
116
  *
117
  * @return false|array - false when logging is disabled, array with log data otherwise
118
- * @see ICWP_BaseProcessor_WPSF::getLogData()
119
  */
120
  public function flushLogData() {
121
 
@@ -138,25 +147,36 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
138
  * @return boolean - true if visitor is permitted, false if it should be blocked.
139
  */
140
  public function doFirewallCheck() {
 
 
 
 
 
141
 
142
  // if we couldn't process the REQUEST_URI parts, we can't firewall so we effectively whitelist without erroring.
143
  $this->setRequestUriPageParts();
144
  if ( empty( $this->m_aRequestUriParts ) ) {
145
- $this->logInfo( 'Could not parse the URI so cannot effectively firewall.' );
146
  return true;
147
  }
148
-
 
 
 
 
 
 
149
  // Set up the page parameters ($_GET and $_POST and optionally $_COOKIE). If there are none, quit since there's nothing for the firewall to check.
150
  $this->setPageParams();
151
  if ( empty( $this->m_aPageParams ) ) {
152
- $this->logInfo( 'After any whitelist options were applied, there were no page parameters to check on this visit.' );
153
  return true;
154
  }
155
  $this->m_aPageParamValuesToCheck = array_values( $this->m_aPageParams );
156
 
157
  if ( $this->m_nRequestIp === false ) {
158
  $this->logCritical(
159
- "Visitor IP address could not be determined so we're by-passing the firewall. Label: %s"
160
  );
161
  return true;
162
  }
@@ -164,37 +184,36 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
164
  // Check if the visitor is excluded from the firewall from the outset.
165
  if ( $this->isVisitorOnWhitelist() ) {
166
  $this->logInfo(
167
- sprintf( 'Visitor is whitelisted by IP Address. Label: %s',
168
- empty( $this->m_sListItemLabel )? 'No label.' : $this->m_sListItemLabel
169
  )
170
  );
 
171
  return true;
172
  }
173
 
174
- //Check if the visitor is excluded from the firewall from the outset.
175
  if ( $this->isVisitorOnBlacklist() ) {
176
  $this->m_sFirewallMessage .= ' Your IP is Blacklisted.';
177
  $this->logWarning(
178
- sprintf( 'Visitor was blacklisted by IP Address. Label: %s',
179
- empty( $this->m_sListItemLabel )? 'No label.' : $this->m_sListItemLabel
180
  )
181
  );
 
182
  return false;
183
  }
184
 
185
- /* Removed as of version 1.5.0
186
- // Checking this comes before all else but after the IP whitelist/blacklist check.
187
- if ( $this->m_aBlockSettings[ 'block_wplogin_access' ] ) {
188
- $fIsPermittedVisitor = $this->doPassCheckBlockWpLogin();
189
- }
190
- */
191
-
192
- $this->logInfo( 'Visitor IP was neither whitelisted nor blacklisted. Firewall checking started.' );
193
 
194
  $fIsPermittedVisitor = true;
195
 
196
  // Check if the page and its parameters are whitelisted.
197
  if ( $fIsPermittedVisitor && $this->isPageWhitelisted() ) {
 
 
 
 
198
  return true;
199
  }
200
 
@@ -210,6 +229,9 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
210
  if ( $fIsPermittedVisitor && $this->m_aBlockSettings[ 'block_field_truncation' ] ) {
211
  $fIsPermittedVisitor = $this->doPassCheckBlockFieldTruncation();
212
  }
 
 
 
213
  if ( $fIsPermittedVisitor && $this->m_aBlockSettings[ 'block_exe_file_uploads' ] ) {
214
  $fIsPermittedVisitor = $this->doPassCheckBlockExeFileUploads();
215
  }
@@ -220,33 +242,6 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
220
  return $fIsPermittedVisitor;
221
  }
222
 
223
- /**
224
- * This function assumes that isVisitorOnWhitelist() check has been run previously. Meaning the
225
- * current visitor is NOT on the whitelist and so if the page they're accessing is wp-login then
226
- * they do not pass this check.
227
- *
228
- * If whitelisted IPs is empty, we never block access.
229
- *
230
- * @return boolean
231
- */
232
- protected function doPassCheckBlockWpLogin() {
233
-
234
- list( $sRequestPage, $sRequestQuery ) = $this->m_aRequestUriParts;
235
-
236
- if ( substr_count( $sRequestPage, '/wp-login.php' ) > 0 ) {
237
-
238
- // We don't block wp-login.php if there are no whitelisted IPs.
239
- if ( count( $this->m_aOptions[ 'ips_whitelist' ] ) < 1 ) {
240
- $this->logInfo( 'Requested: Block access to wp-login.php, but this was skipped because whitelisted IPs list was empty.' );
241
- return true;
242
- }
243
-
244
- $this->logWarning( 'Requested: Block access to wp-login.php. Visitor not on IP whitelist and blocked by firewall.' );
245
- return false;
246
- }
247
- return true;
248
- }
249
-
250
  protected function doPassCheckBlockDirTraversal() {
251
  $aTerms = array(
252
  'etc/passwd',
@@ -255,7 +250,8 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
255
  );
256
  $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms );
257
  if ( !$fPass ) {
258
- $this->logWarning( 'Blocked Directory Traversal.' );
 
259
  }
260
  return $fPass;
261
  }
@@ -268,7 +264,8 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
268
  );
269
  $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms, true );
270
  if ( !$fPass ) {
271
- $this->logWarning( 'Requested: Block access to wp-login.php, but this was skipped because whitelisted IPs list was empty.' );
 
272
  }
273
  return $fPass;
274
  }
@@ -281,9 +278,11 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
281
  '/0x[0-9a-f][0-9a-f]/i',
282
  '/\/\*\*\//'
283
  );
 
284
  $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms, true );
285
  if ( !$fPass ) {
286
- $this->logWarning( 'Blocked WordPress Terms.' );
 
287
  }
288
  return $fPass;
289
  }
@@ -295,11 +294,24 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
295
  );
296
  $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms, true );
297
  if ( !$fPass ) {
298
- $this->logWarning( 'Blocked Field Truncation.' );
 
299
  }
300
  return $fPass;
301
  }
302
-
 
 
 
 
 
 
 
 
 
 
 
 
303
  protected function doPassCheckBlockExeFileUploads() {
304
  $aTerms = array(
305
  '/\.dll$/i', '/\.rb$/i', '/\.py$/i', '/\.exe$/i', '/\.php[3-6]?$/i', '/\.pl$/i',
@@ -315,7 +327,8 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
315
  }
316
  $fPass = $this->doPassCheck( $aFileNames, $aTerms, true );
317
  if ( !$fPass ) {
318
- $this->logWarning( 'Blocked EXE File Uploads.' );
 
319
  }
320
  return $fPass;
321
  }
@@ -328,7 +341,8 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
328
  );
329
  $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms, true );
330
  if ( !$fPass ) {
331
- $this->logWarning( 'Blocked Leading Schema.' );
 
332
  }
333
  return $fPass;
334
  }
@@ -375,7 +389,7 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
375
  if ( $fFAIL ) {
376
  $this->m_sFirewallMessage .= " Something in the URL, Form or Cookie data wasn't appropriate.";
377
  $this->logWarning(
378
- sprintf( 'Page parameter failed firewall check. The value was %s and the term matched was %s', $mValue, $sTerm )
379
  );
380
  return false;
381
  }
@@ -392,22 +406,22 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
392
  switch( $this->m_aOptions['block_response'] ) {
393
  case 'redirect_die':
394
  $this->logWarning(
395
- sprintf( 'Firewall Block: Visitor connection was killed with %s', 'die()' )
396
  );
397
  break;
398
  case 'redirect_die_message':
399
  $this->logWarning(
400
- sprintf( 'Firewall Block: Visitor connection was killed with %s and message', 'wp_die()' )
401
  );
402
  break;
403
  case 'redirect_home':
404
  $this->logWarning(
405
- sprintf( 'Firewall Block: Visitor was sent HOME: %s', home_url() )
406
  );
407
  break;
408
  case 'redirect_404':
409
  $this->logWarning(
410
- sprintf( 'Firewall Block: Visitor was sent 404: %s', home_url().'/404' )
411
  );
412
  break;
413
  }
@@ -421,10 +435,9 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
421
 
422
  switch( $this->m_aOptions['block_response'] ) {
423
  case 'redirect_die':
424
- die();
425
  case 'redirect_die_message':
426
  wp_die( $this->m_sFirewallMessage );
427
- exit();
428
  break;
429
  case 'redirect_home':
430
  header( "Location: ".home_url() );
@@ -432,17 +445,18 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
432
  break;
433
  case 'redirect_404':
434
  header( "Location: ".home_url().'/404' );
435
- exit();
 
436
  break;
437
  }
 
438
  }
439
 
440
  /**
441
- *
442
  * @return boolean
443
  */
444
  public function isPageWhitelisted() {
445
- return empty( $this->m_aPageParams );
446
  }
447
 
448
  public function filterWhitelistedPagesAndParams() {
@@ -477,7 +491,7 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
477
 
478
  // Now we compare pages in the whitelist with the parts of the request uri. If we get a match, that page is whitelisted
479
  $aWhitelistPages = array_keys( $inaWhitelistPagesParams );
480
-
481
  // 1. Is the page in the list of white pages?
482
  $fPageWhitelisted = false;
483
  foreach ( $inaWhitelistPagesParams as $sPageName => $aWhitlistedParams ) {
@@ -489,7 +503,9 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
489
  }
490
  }
491
  else {
492
- if ( preg_match( self::PcreDelimiter. preg_quote( $sPageName, self::PcreDelimiter ).'$'.self::PcreDelimiter, $sRequestPage ) ) {
 
 
493
  $fPageWhitelisted = true;
494
  break;
495
  }
@@ -505,10 +521,11 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
505
  }
506
  }
507
 
508
- // There's a list of globally whitelisted parameters (i.e. parameter ignored for all pages)
509
  if ( $fPageWhitelisted ) {
510
  // the current page is whitelisted - now check if it has request parameters.
511
  if ( empty( $aWhitlistedParams ) ) {
 
512
  return true; //because it's just plain whitelisted as represented by an empty or unset array
513
  }
514
  foreach ( $aWhitlistedParams as $sWhitelistParam ) {
@@ -520,6 +537,7 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
520
  // After removing all the whitelisted params, we now check if there are any params left that'll
521
  // need matched later in the firewall checking. If there are no parameters left, we return true.
522
  if ( empty( $this->m_aPageParams ) ) {
 
523
  return true;
524
  }
525
  }
@@ -530,11 +548,15 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
530
 
531
  if ( !isset( $_SERVER['REQUEST_URI'] ) || empty( $_SERVER['REQUEST_URI'] ) ) {
532
  $this->m_aRequestUriParts = false;
533
- $this->logWarning( 'Could not parse the details of this page call as $_SERVER[REQUEST_URI] was empty or not defined.' );
 
 
534
  return false;
535
  }
536
  $this->m_aRequestUriParts = explode( '?', $_SERVER['REQUEST_URI'] );
537
- $this->logInfo( sprintf( 'Page Request URI: %s', $_SERVER['REQUEST_URI'] ) );
 
 
538
  return true;
539
  }
540
 
@@ -547,6 +569,9 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
547
  if ( !empty( $this->m_aPageParams ) ) {
548
  $this->filterWhitelistedPagesAndParams();
549
  }
 
 
 
550
  return true;
551
  }
552
 
@@ -558,7 +583,8 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
558
  '/wp-admin/page-new.php' => array(),
559
  '/wp-admin/link-add.php' => array(),
560
  '/wp-admin/media-upload.php' => array(),
561
- '/wp-admin/post.php' => array(),
 
562
  '/wp-admin/page.php' => array(),
563
  '/wp-admin/admin-ajax.php' => array(),
564
  '/wp-comments-post.php' => array(
@@ -600,21 +626,24 @@ class ICWP_FirewallProcessor extends ICWP_BaseProcessor_WPSF {
600
 
601
  $sIp = long2ip( $this->m_nRequestIp );
602
  $aMessage = array(
603
- 'WordPress Simple Firewall has blocked a visitor to your site.',
604
- 'Log details for this visitor are below:',
605
- '- IP Address: '.$sIp,
606
  );
607
  foreach( $this->m_aLogMessages as $aLogItem ) {
608
  list( $sLogType, $sLogMessage ) = $aLogItem;
609
- $aMessage[] = '- '.$sLogMessage;
610
  }
611
-
612
- $sEmailSubject = 'Firewall Block Alert: ' . home_url();
613
- $aMessage[] = 'You could look up the offending IP Address here: http://ip-lookup.net/?ip='.$sIp;
614
-
615
- $this->logInfo( 'Firewall block email.' );
616
  $this->sendEmail( $sEmailSubject, $aMessage );
 
617
  }
618
  }
619
 
 
 
 
 
620
  endif;
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
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
+ const Slug = 'firewall';
25
 
26
  protected $m_nRequestTimestamp;
27
 
36
  private $m_nLoopProtect;
37
  private $m_sFirewallMessage;
38
 
39
+ /**
40
+ * @var boolean
41
+ */
42
+ protected $m_fRequestIsWhitelisted;
43
+
44
  /**
45
  * @var string
46
  */
70
  */
71
  protected $m_aPageParamValues;
72
 
73
+ public function __construct( $insOptionPrefix = '' ) {
74
+ parent::__construct( $this->constructStorageKey( $insOptionPrefix, self::Slug ) );
75
 
76
  $sMessage = "You were blocked by the %sWordPress Simple Firewall%s.";
77
  $this->m_sFirewallMessage = sprintf( $sMessage, '<a href="http://wordpress.org/plugins/wp-simple-firewall/" target="_blank">', '</a>');
78
  }
79
 
80
  /**
81
+ * @see ICWP_WPSF_BaseProcessor::setOptions()
82
  */
83
  public function setOptions( &$inaOptions ) {
84
  parent::setOptions( $inaOptions );
90
  'block_sql_queries',
91
  'block_wordpress_terms',
92
  'block_field_truncation',
93
+ 'block_php_code',
94
  'block_exe_file_uploads',
95
  'block_leading_schema'
96
  );
97
  $this->m_aBlockSettings = array();
98
  foreach( $aSettingSlugs as $sSettingKey ) {
99
+ $this->m_aBlockSettings[ $sSettingKey ] = $this->getOption( $sSettingKey ) == 'Y';
100
  }
101
 
102
  $this->m_aCustomWhitelistPageParams = is_array( $this->m_aOptions[ 'page_params_whitelist' ] )? $this->m_aOptions[ 'page_params_whitelist' ] : array();
103
+ $this->setLogging( $this->getOption('enable_firewall_log') == 'Y' );
104
  }
105
 
106
  /**
117
  parent::reset();
118
  $this->m_nRequestTimestamp = time();
119
  $this->m_nLoopProtect = 0;
120
+ $this->m_fRequestIsWhitelisted = false;
121
  }
122
 
123
  /**
124
  * Should return false when logging is disabled.
125
  *
126
  * @return false|array - false when logging is disabled, array with log data otherwise
127
+ * @see ICWP_WPSF_BaseProcessor::getLogData()
128
  */
129
  public function flushLogData() {
130
 
147
  * @return boolean - true if visitor is permitted, false if it should be blocked.
148
  */
149
  public function doFirewallCheck() {
150
+
151
+ if ( $this->getOption('whitelist_admins') == 'Y' && is_super_admin() ) {
152
+ $this->logInfo( _wpsf__('Logged-in administrators currently by-pass all firewall checking.') );
153
+ return true;
154
+ }
155
 
156
  // if we couldn't process the REQUEST_URI parts, we can't firewall so we effectively whitelist without erroring.
157
  $this->setRequestUriPageParts();
158
  if ( empty( $this->m_aRequestUriParts ) ) {
159
+ $this->logInfo( _wpsf__('Cannot Run Firewall checking because parsing the URI failed.') );
160
  return true;
161
  }
162
+
163
+ $this->loadDataProcessor();
164
+ if ( $this->getOption('ignore_search_engines') == 'Y' && ICWP_WPSF_DataProcessor::IsSearchEngineBot() ) {
165
+ $this->logInfo( _wpsf__('Visitor detected as Search Engine Bot so by-passing Firewall Checking.') );
166
+ return true;
167
+ }
168
+
169
  // Set up the page parameters ($_GET and $_POST and optionally $_COOKIE). If there are none, quit since there's nothing for the firewall to check.
170
  $this->setPageParams();
171
  if ( empty( $this->m_aPageParams ) ) {
172
+ $this->logInfo( _wpsf__('After whitelist options were applied, there were no page parameters to check on this visit.') );
173
  return true;
174
  }
175
  $this->m_aPageParamValuesToCheck = array_values( $this->m_aPageParams );
176
 
177
  if ( $this->m_nRequestIp === false ) {
178
  $this->logCritical(
179
+ _wpsf__("Visitor IP address could not be determined so by-passing the Firewall.")
180
  );
181
  return true;
182
  }
184
  // Check if the visitor is excluded from the firewall from the outset.
185
  if ( $this->isVisitorOnWhitelist() ) {
186
  $this->logInfo(
187
+ sprintf( _wpsf__('Visitor is white-listed by IP Address. Label: %s'),
188
+ empty( $this->m_sListItemLabel )? _wpsf__('No label.') : $this->m_sListItemLabel
189
  )
190
  );
191
+ $this->doStatIncrement( 'firewall.allowed.whitelist' );
192
  return true;
193
  }
194
 
195
+ // Check if the visitor is excluded from the firewall from the outset.
196
  if ( $this->isVisitorOnBlacklist() ) {
197
  $this->m_sFirewallMessage .= ' Your IP is Blacklisted.';
198
  $this->logWarning(
199
+ sprintf( _wpsf__('Visitor was black-listed by IP Address. Label: %s'),
200
+ empty( $this->m_sListItemLabel )? _wpsf__('No label.') : $this->m_sListItemLabel
201
  )
202
  );
203
+ $this->doStatIncrement( 'firewall.blocked.blacklist' );
204
  return false;
205
  }
206
 
207
+ $this->logInfo( _wpsf__('Visitor IP was neither white-listed nor black-listed. Firewall checking started...') );
 
 
 
 
 
 
 
208
 
209
  $fIsPermittedVisitor = true;
210
 
211
  // Check if the page and its parameters are whitelisted.
212
  if ( $fIsPermittedVisitor && $this->isPageWhitelisted() ) {
213
+ $this->logWarning(
214
+ _wpsf__('All page request parameters were white-listed.' )
215
+ );
216
+ $this->doStatIncrement( 'firewall.allowed.pagewhitelist' );
217
  return true;
218
  }
219
 
229
  if ( $fIsPermittedVisitor && $this->m_aBlockSettings[ 'block_field_truncation' ] ) {
230
  $fIsPermittedVisitor = $this->doPassCheckBlockFieldTruncation();
231
  }
232
+ if ( $fIsPermittedVisitor && $this->m_aBlockSettings[ 'block_php_code' ] ) {
233
+ $fIsPermittedVisitor = $this->doPassCheckPhpCode();
234
+ }
235
  if ( $fIsPermittedVisitor && $this->m_aBlockSettings[ 'block_exe_file_uploads' ] ) {
236
  $fIsPermittedVisitor = $this->doPassCheckBlockExeFileUploads();
237
  }
242
  return $fIsPermittedVisitor;
243
  }
244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  protected function doPassCheckBlockDirTraversal() {
246
  $aTerms = array(
247
  'etc/passwd',
250
  );
251
  $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms );
252
  if ( !$fPass ) {
253
+ $this->logWarning( sprintf( _wpsf__('Firewall Blocked: %s'), _wpsf__('Directory Traversal') ) );
254
+ $this->doStatIncrement( 'firewall.blocked.dirtraversal' );
255
  }
256
  return $fPass;
257
  }
264
  );
265
  $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms, true );
266
  if ( !$fPass ) {
267
+ $this->logWarning( sprintf( _wpsf__('Firewall Blocked: %s'), _wpsf__('SQL Queries') ) );
268
+ $this->doStatIncrement( 'firewall.blocked.sqlqueries' );
269
  }
270
  return $fPass;
271
  }
278
  '/0x[0-9a-f][0-9a-f]/i',
279
  '/\/\*\*\//'
280
  );
281
+
282
  $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms, true );
283
  if ( !$fPass ) {
284
+ $this->logWarning( sprintf( _wpsf__('Firewall Blocked: %s'), _wpsf__('WordPress Terms') ) );
285
+ $this->doStatIncrement( 'firewall.blocked.wpterms' );
286
  }
287
  return $fPass;
288
  }
294
  );
295
  $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms, true );
296
  if ( !$fPass ) {
297
+ $this->logWarning( sprintf( _wpsf__('Firewall Blocked: %s'), _wpsf__('Field Truncation') ) );
298
+ $this->doStatIncrement( 'firewall.blocked.fieldtruncation' );
299
  }
300
  return $fPass;
301
  }
302
+
303
+ protected function doPassCheckPhpCode() {
304
+ $aTerms = array(
305
+ '/(include|include_once|require|require_once)(\s*\(|\s*\'|\s*"|\s+\w+)/i'
306
+ );
307
+ $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms, true );
308
+ if ( !$fPass ) {
309
+ $this->logWarning( sprintf( _wpsf__('Firewall Blocked: %s'), _wpsf__('PHP Code') ) );
310
+ $this->doStatIncrement( 'firewall.blocked.phpcode' );
311
+ }
312
+ return $fPass;
313
+ }
314
+
315
  protected function doPassCheckBlockExeFileUploads() {
316
  $aTerms = array(
317
  '/\.dll$/i', '/\.rb$/i', '/\.py$/i', '/\.exe$/i', '/\.php[3-6]?$/i', '/\.pl$/i',
327
  }
328
  $fPass = $this->doPassCheck( $aFileNames, $aTerms, true );
329
  if ( !$fPass ) {
330
+ $this->logWarning( sprintf( _wpsf__('Firewall Blocked: %s'), _wpsf__('EXE File Uploads') ) );
331
+ $this->doStatIncrement( 'firewall.blocked.exefile' );
332
  }
333
  return $fPass;
334
  }
341
  );
342
  $fPass = $this->doPassCheck( $this->m_aPageParamValuesToCheck, $aTerms, true );
343
  if ( !$fPass ) {
344
+ $this->logWarning( sprintf( _wpsf__('Firewall Blocked: %s'), _wpsf__('Leading Schema') ) );
345
+ $this->doStatIncrement( 'firewall.blocked.schema' );
346
  }
347
  return $fPass;
348
  }
389
  if ( $fFAIL ) {
390
  $this->m_sFirewallMessage .= " Something in the URL, Form or Cookie data wasn't appropriate.";
391
  $this->logWarning(
392
+ sprintf( 'Page parameter failed firewall check. The offending value was %s', $mValue )
393
  );
394
  return false;
395
  }
406
  switch( $this->m_aOptions['block_response'] ) {
407
  case 'redirect_die':
408
  $this->logWarning(
409
+ sprintf( _wpsf__('Firewall Block Response: %s'), _wpsf__('Visitor connection was killed with wp_die()') )
410
  );
411
  break;
412
  case 'redirect_die_message':
413
  $this->logWarning(
414
+ sprintf( _wpsf__('Firewall Block Response: %s'), _wpsf__('Visitor connection was killed with wp_die() and message') )
415
  );
416
  break;
417
  case 'redirect_home':
418
  $this->logWarning(
419
+ sprintf( _wpsf__('Firewall Block Response: %s'), _wpsf__('Visitor was sent HOME') )
420
  );
421
  break;
422
  case 'redirect_404':
423
  $this->logWarning(
424
+ sprintf( _wpsf__('Firewall Block Response: %s'), _wpsf__('Visitor was sent 404') )
425
  );
426
  break;
427
  }
435
 
436
  switch( $this->m_aOptions['block_response'] ) {
437
  case 'redirect_die':
438
+ break;
439
  case 'redirect_die_message':
440
  wp_die( $this->m_sFirewallMessage );
 
441
  break;
442
  case 'redirect_home':
443
  header( "Location: ".home_url() );
445
  break;
446
  case 'redirect_404':
447
  header( "Location: ".home_url().'/404' );
448
+ break;
449
+ default:
450
  break;
451
  }
452
+ exit();
453
  }
454
 
455
  /**
 
456
  * @return boolean
457
  */
458
  public function isPageWhitelisted() {
459
+ return empty( $this->m_aPageParams ) || $this->m_fRequestIsWhitelisted;
460
  }
461
 
462
  public function filterWhitelistedPagesAndParams() {
491
 
492
  // Now we compare pages in the whitelist with the parts of the request uri. If we get a match, that page is whitelisted
493
  $aWhitelistPages = array_keys( $inaWhitelistPagesParams );
494
+
495
  // 1. Is the page in the list of white pages?
496
  $fPageWhitelisted = false;
497
  foreach ( $inaWhitelistPagesParams as $sPageName => $aWhitlistedParams ) {
503
  }
504
  }
505
  else {
506
+ $sWhitelistedPageAsPreg = preg_quote( $sPageName, self::PcreDelimiter );
507
+ $sWhitelistedPageAsPreg = sprintf( '%s%s$%s', self::PcreDelimiter, $sWhitelistedPageAsPreg, self::PcreDelimiter );
508
+ if ( preg_match( $sWhitelistedPageAsPreg, $sRequestPage ) ) {
509
  $fPageWhitelisted = true;
510
  break;
511
  }
521
  }
522
  }
523
 
524
+ // Given the page is found to be on the whitelist, we want to check if it's the whole page, or certain parameters only
525
  if ( $fPageWhitelisted ) {
526
  // the current page is whitelisted - now check if it has request parameters.
527
  if ( empty( $aWhitlistedParams ) ) {
528
+ $this->m_fRequestIsWhitelisted = true;
529
  return true; //because it's just plain whitelisted as represented by an empty or unset array
530
  }
531
  foreach ( $aWhitlistedParams as $sWhitelistParam ) {
537
  // After removing all the whitelisted params, we now check if there are any params left that'll
538
  // need matched later in the firewall checking. If there are no parameters left, we return true.
539
  if ( empty( $this->m_aPageParams ) ) {
540
+ $this->m_fRequestIsWhitelisted = true;
541
  return true;
542
  }
543
  }
548
 
549
  if ( !isset( $_SERVER['REQUEST_URI'] ) || empty( $_SERVER['REQUEST_URI'] ) ) {
550
  $this->m_aRequestUriParts = false;
551
+ $this->logWarning(
552
+ sprintf( _wpsf__('Could not parse the details of this page call as "%s" was empty or not defined '), $_SERVER['REQUEST_URI'] )
553
+ );
554
  return false;
555
  }
556
  $this->m_aRequestUriParts = explode( '?', $_SERVER['REQUEST_URI'] );
557
+ $this->logInfo(
558
+ sprintf( _wpsf__('Page Request URI: %s'), $_SERVER['REQUEST_URI'] )
559
+ );
560
  return true;
561
  }
562
 
569
  if ( !empty( $this->m_aPageParams ) ) {
570
  $this->filterWhitelistedPagesAndParams();
571
  }
572
+ else {
573
+ $this->m_fRequestIsWhitelisted = true;
574
+ }
575
  return true;
576
  }
577
 
583
  '/wp-admin/page-new.php' => array(),
584
  '/wp-admin/link-add.php' => array(),
585
  '/wp-admin/media-upload.php' => array(),
586
+ '/wp-admin/post.php' => array( 'content' ),
587
+ '/wp-admin/plugin-editor.php' => array( 'newcontent' ),
588
  '/wp-admin/page.php' => array(),
589
  '/wp-admin/admin-ajax.php' => array(),
590
  '/wp-comments-post.php' => array(
626
 
627
  $sIp = long2ip( $this->m_nRequestIp );
628
  $aMessage = array(
629
+ _wpsf__('WordPress Simple Firewall has blocked a page visit to your site.'),
630
+ _wpsf__('Log details for this visitor are below:'),
631
+ '- '.sprintf( _wpsf__('IP Address: %s'), $sIp )
632
  );
633
  foreach( $this->m_aLogMessages as $aLogItem ) {
634
  list( $sLogType, $sLogMessage ) = $aLogItem;
635
+ $aMessage[] = '- '.$sLogMessage;
636
  }
637
+ $aMessage[] = sprintf( _wpsf__('You can look up the offending IP Address here: %s'), 'http://ip-lookup.net/?ip='.$sIp );
638
+
639
+ $sEmailSubject = sprintf( _wpsf__('Firewall Block Email Alert: %s'), home_url() );
 
 
640
  $this->sendEmail( $sEmailSubject, $aMessage );
641
+ $this->logInfo( _wpsf__('Firewall block email alert sent.') );
642
  }
643
  }
644
 
645
+ endif;
646
+
647
+ if ( !class_exists('ICWP_WPSF_FirewallProcessor') ):
648
+ class ICWP_WPSF_FirewallProcessor extends ICWP_FirewallProcessor_V1 { }
649
  endif;
src/icwp-processor-lockdown.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -17,50 +17,67 @@
17
 
18
  require_once( dirname(__FILE__).'/icwp-base-processor.php' );
19
 
20
- if ( !class_exists('ICWP_LockdownProcessor') ):
21
 
22
- class ICWP_LockdownProcessor extends ICWP_BaseProcessor_WPSF {
23
-
24
- /**
25
- * Resets the object values to be re-used anew
26
- */
27
- public function reset() {
28
- parent::reset();
29
  }
30
-
31
  /**
32
  */
33
  public function run() {
34
 
35
- if ( $this->m_aOptions['disable_file_editing'] == 'Y' ) {
 
 
 
36
  add_filter( 'user_has_cap', array( $this, 'disableFileEditing' ), 0, 3 );
37
  }
38
-
39
- if ( !empty( $this->m_aOptions['mask_wordpress_version'] ) ) {
 
40
  global $wp_version;
41
- $wp_version = $this->m_aOptions['mask_wordpress_version'];
42
  // add_filter( 'bloginfo', array( $this, 'maskWordpressVersion' ), 1, 2 );
43
  // add_filter( 'bloginfo_url', array( $this, 'maskWordpressVersion' ), 1, 2 );
44
- }
45
 
46
- if ( false && $this->m_aOptions['action_reset_auth_salts'] == 'Y' ) {
47
  add_action( 'init', array( $this, 'resetAuthKeysSalts' ), 1 );
48
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
50
-
51
  /**
52
  * @return array
53
  */
54
- public function disableFileEditing( $inaAllCaps, $cap, $inaArgs ) {
55
 
56
  $aEditCapabilities = array( 'edit_themes', 'edit_plugins', 'edit_files' );
57
- $sRequestedCapability = $inaArgs[0];
58
 
59
  if ( !in_array( $sRequestedCapability, $aEditCapabilities ) ) {
60
- return $inaAllCaps;
61
  }
62
- $inaAllCaps[ $sRequestedCapability ] = false;
63
- return $inaAllCaps;
64
  }
65
 
66
  /**
@@ -77,15 +94,13 @@ class ICWP_LockdownProcessor extends ICWP_BaseProcessor_WPSF {
77
  *
78
  */
79
  public function resetAuthKeysSalts() {
80
-
81
- require_once( dirname(__FILE__).'/icwp-wpfilesystem.php' );
82
- $oWpFilesystem = new ICWP_WpFilesystem_WPSF();
83
 
84
  // Get the new Salts
85
  $sSaltsUrl = 'https://api.wordpress.org/secret-key/1.1/salt/';
86
- $sSalts = $oWpFilesystem->getUrlContent( $sSaltsUrl );
87
 
88
- $sWpConfigContent = $oWpFilesystem->getContent_WpConfig();
89
  if ( is_null( $sWpConfigContent ) ) {
90
  return;
91
  }
@@ -119,8 +134,12 @@ class ICWP_LockdownProcessor extends ICWP_BaseProcessor_WPSF {
119
  }
120
  }
121
  $aContent[$nStartLine] = $sSalts;
122
- $oWpFilesystem->putContent_WpConfig( implode( PHP_EOL, $aContent ) );
123
  }
124
  }
125
 
 
 
 
 
126
  endif;
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
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
+ const Slug = 'lockdown';
25
+
26
+ public function __construct( $insOptionPrefix = '' ) {
27
+ parent::__construct( $this->constructStorageKey( $insOptionPrefix, self::Slug ) );
 
28
  }
29
+
30
  /**
31
  */
32
  public function run() {
33
 
34
+ if ( $this->getIsOption( 'disable_file_editing', 'Y' ) ) {
35
+ if ( !defined('DISALLOW_FILE_EDIT') ) {
36
+ define( 'DISALLOW_FILE_EDIT', true );
37
+ }
38
  add_filter( 'user_has_cap', array( $this, 'disableFileEditing' ), 0, 3 );
39
  }
40
+
41
+ $sWpVersionMask = $this->getOption('mask_wordpress_version');
42
+ if ( !empty( $sWpVersionMask ) ) {
43
  global $wp_version;
44
+ $wp_version = $sWpVersionMask;
45
  // add_filter( 'bloginfo', array( $this, 'maskWordpressVersion' ), 1, 2 );
46
  // add_filter( 'bloginfo_url', array( $this, 'maskWordpressVersion' ), 1, 2 );
47
+ }
48
 
49
+ if ( false && $this->getOption('action_reset_auth_salts') == 'Y' ) {
50
  add_action( 'init', array( $this, 'resetAuthKeysSalts' ), 1 );
51
  }
52
+
53
+ if ( $this->getIsOption( 'force_ssl_login', 'Y' ) && function_exists('force_ssl_login') ) {
54
+ if ( !defined('FORCE_SSL_LOGIN') ) {
55
+ define( 'FORCE_SSL_LOGIN', true );
56
+ }
57
+ force_ssl_login( true );
58
+ }
59
+
60
+ if ( $this->getIsOption( 'force_ssl_admin', 'Y' ) && function_exists('force_ssl_admin') ) {
61
+ if ( !defined('FORCE_SSL_ADMIN') ) {
62
+ define( 'FORCE_SSL_ADMIN', true );
63
+ }
64
+ force_ssl_admin( true );
65
+ }
66
  }
67
+
68
  /**
69
  * @return array
70
  */
71
+ public function disableFileEditing( $aAllCaps, $cap, $aArgs ) {
72
 
73
  $aEditCapabilities = array( 'edit_themes', 'edit_plugins', 'edit_files' );
74
+ $sRequestedCapability = $aArgs[0];
75
 
76
  if ( !in_array( $sRequestedCapability, $aEditCapabilities ) ) {
77
+ return $aAllCaps;
78
  }
79
+ $aAllCaps[ $sRequestedCapability ] = false;
80
+ return $aAllCaps;
81
  }
82
 
83
  /**
94
  *
95
  */
96
  public function resetAuthKeysSalts() {
97
+ $oWpFs = $this->loadFileSystemProcessor();
 
 
98
 
99
  // Get the new Salts
100
  $sSaltsUrl = 'https://api.wordpress.org/secret-key/1.1/salt/';
101
+ $sSalts = $oWpFs->getUrlContent( $sSaltsUrl );
102
 
103
+ $sWpConfigContent = $oWpFs->getContent_WpConfig();
104
  if ( is_null( $sWpConfigContent ) ) {
105
  return;
106
  }
134
  }
135
  }
136
  $aContent[$nStartLine] = $sSalts;
137
+ $oWpFs->putContent_WpConfig( implode( PHP_EOL, $aContent ) );
138
  }
139
  }
140
 
141
+ endif;
142
+
143
+ if ( !class_exists('ICWP_WPSF_LockdownProcessor') ):
144
+ class ICWP_WPSF_LockdownProcessor extends ICWP_LockdownProcessor_V1 { }
145
  endif;
src/icwp-processor-logging.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -17,25 +17,28 @@
17
 
18
  require_once( dirname(__FILE__).'/icwp-basedb-processor.php' );
19
 
20
- if ( !class_exists('ICWP_LoggingProcessor') ):
21
 
22
- class ICWP_LoggingProcessor extends ICWP_BaseDbProcessor_WPSF {
23
 
 
24
  const TableName = 'wpsf_log';
 
 
25
  protected $m_sRequestId;
26
-
27
- public function __construct() {
28
- parent::__construct( self::TableName );
29
  $this->createTable();
30
  }
31
-
32
  public function reset() {
33
  parent::reset();
34
  $this->m_sRequestId = uniqid();
35
- $this->m_nRequestIp = self::GetVisitorIpAddress();
36
  }
37
 
38
  /**
 
39
  * @return array - numerical array of all log data entries.
40
  */
41
  public function getLogs( $infReverseOrder = false ) {
@@ -47,19 +50,12 @@ class ICWP_LoggingProcessor extends ICWP_BaseDbProcessor_WPSF {
47
  }
48
 
49
  /**
50
- * @return array - numerical array of all log data entries.
 
 
 
51
  */
52
- public function writeLog( $inaLogData ) {
53
-
54
- if ( empty( $inaLogData ) || empty( $inaLogData['messages'] ) ) {
55
- return;
56
- }
57
- $aData = $this->completeLogData( $inaLogData );
58
- $fSuccess = $this->insertIntoTable( $aData );
59
- return $fSuccess;
60
- }
61
-
62
- protected function completeLogData( $inaLogData ) {
63
 
64
  if ( !isset( $inaLogData['category'] ) ) {
65
  $inaLogData['category'] = self::LOG_CATEGORY_DEFAULT;
@@ -80,7 +76,6 @@ class ICWP_LoggingProcessor extends ICWP_BaseDbProcessor_WPSF {
80
  }
81
 
82
  public function createTable() {
83
-
84
  // Set up log table
85
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
86
  `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -103,6 +98,23 @@ class ICWP_LoggingProcessor extends ICWP_BaseDbProcessor_WPSF {
103
  $this->recreateTable();
104
  }
105
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  }
107
 
 
 
 
 
108
  endif;
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
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 Slug = 'logging';
25
  const TableName = 'wpsf_log';
26
+ const DaysToKeepLog = 7;
27
+
28
  protected $m_sRequestId;
29
+
30
+ public function __construct( $insOptionPrefix = '' ) {
31
+ parent::__construct( $this->constructStorageKey( $insOptionPrefix, self::Slug ), self::TableName );
32
  $this->createTable();
33
  }
34
+
35
  public function reset() {
36
  parent::reset();
37
  $this->m_sRequestId = uniqid();
 
38
  }
39
 
40
  /**
41
+ * @param boolean $infReverseOrder
42
  * @return array - numerical array of all log data entries.
43
  */
44
  public function getLogs( $infReverseOrder = false ) {
50
  }
51
 
52
  /**
53
+ * Ensures the log data provided has all the necessary data points to be written to the DB
54
+ *
55
+ * @param array $inaLogData
56
+ * @return array
57
  */
58
+ protected function completeDataForWrite( $inaLogData ) {
 
 
 
 
 
 
 
 
 
 
59
 
60
  if ( !isset( $inaLogData['category'] ) ) {
61
  $inaLogData['category'] = self::LOG_CATEGORY_DEFAULT;
76
  }
77
 
78
  public function createTable() {
 
79
  // Set up log table
80
  $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
81
  `id` int(11) NOT NULL AUTO_INCREMENT,
98
  $this->recreateTable();
99
  }
100
  }
101
+
102
+ /**
103
+ * This is hooked into a cron in the base class and overrides the parent method.
104
+ *
105
+ * It'll delete everything older than 7 days.
106
+ */
107
+ public function cleanupDatabase() {
108
+ if ( !$this->getTableExists() ) {
109
+ return;
110
+ }
111
+ $nTimeStamp = time() - DAY_IN_SECONDS * self::DaysToKeepLog;
112
+ $this->deleteAllRowsOlderThan( $nTimeStamp );
113
+ }
114
  }
115
 
116
+ endif;
117
+
118
+ if ( !class_exists('ICWP_WPSF_LoggingProcessor') ):
119
+ class ICWP_WPSF_LoggingProcessor extends ICWP_LoggingProcessor_V1 { }
120
  endif;
src/icwp-processor-loginprotect.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
@@ -17,12 +17,15 @@
17
 
18
  require_once( dirname(__FILE__).'/icwp-basedb-processor.php' );
19
 
20
- if ( !class_exists('ICWP_LoginProtectProcessor') ):
21
 
22
- class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
23
 
 
24
  const TableName = 'login_auth';
25
-
 
 
26
  /**
27
  * @var string
28
  */
@@ -33,11 +36,23 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
33
  * @var integer
34
  */
35
  protected $m_nRequiredLoginInterval;
36
-
 
 
 
37
  protected $m_nLastLoginTime;
 
 
 
38
  protected $m_sSecretKey;
39
-
 
 
40
  protected $m_sGaspKey;
 
 
 
 
41
 
42
  /**
43
  * Flag as to whether Two Factor Authentication will be by-pass when sending the verification
@@ -46,14 +61,11 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
46
  * @var boolean
47
  */
48
  protected $m_fAllowTwoFactorByPass;
49
-
50
- public function __construct() {
51
- parent::__construct( self::TableName );
52
 
 
 
53
  $this->m_sGaspKey = uniqid();
54
- self::$sModeFile_LoginThrottled = dirname( __FILE__ ).'/../mode.login_throttled';
55
  $this->updateLastLoginThrottleTime( time() );
56
-
57
  $this->createTable();
58
  $this->reset();
59
  }
@@ -63,6 +75,21 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
63
  */
64
  public function reset() {
65
  parent::reset();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  }
67
 
68
  /**
@@ -72,13 +99,16 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
72
  */
73
  public function setSecretKey( $insSecretKey = '' ) {
74
  if ( !empty( $insSecretKey ) ) {
 
 
 
75
  $this->m_sSecretKey = $insSecretKey;
76
  }
77
  }
78
 
79
  /**
80
  *
81
- * @param array $inoOptions
82
  */
83
  public function setOptions( &$inaOptions ) {
84
  parent::setOptions( $inaOptions );
@@ -91,76 +121,148 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
91
  * @return boolean
92
  */
93
  public function getNeedsEmailHandler() {
94
- if ( isset( $this->m_aOptions['enable_two_factor_auth_by_ip'] ) && $this->m_aOptions['enable_two_factor_auth_by_ip'] == 'Y' ) {
95
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  }
97
- return false;
98
  }
99
 
100
- public function setLogging() {
101
- parent::setLogging( $this->m_aOptions[ 'enable_login_protect_log' ] == 'Y' );
102
  }
103
 
104
  /**
105
- * @param ICWP_OptionsHandler_LoginProtect $inoOptions
106
  */
107
  public function run() {
108
- $aWhitelist = $this->m_aOptions['ips_whitelist'];
 
 
 
 
 
 
 
109
  if ( !empty( $aWhitelist ) && $this->isIpOnlist( $aWhitelist, self::GetVisitorIpAddress() ) ) {
110
  return true;
111
  }
112
-
 
 
 
 
 
113
  // Add GASP checking to the login form.
114
- if ( $this->m_aOptions['enable_login_gasp_check'] == 'Y' ) {
115
  add_action( 'login_form', array( $this, 'printGaspLoginCheck_Action' ) );
116
  add_filter( 'login_form_middle', array( $this, 'printGaspLoginCheck_Filter' ) );
117
- add_filter( 'authenticate', array( $this, 'checkLoginForGasp_Filter' ), 9, 3);
 
118
  }
119
 
120
- if ( $this->m_aOptions['login_limit_interval'] > 0 ) {
 
121
  // We give it a priority of 10 so that we can jump in before WordPress does its own validation.
122
  add_filter( 'authenticate', array( $this, 'checkLoginInterval_Filter' ), 10, 3);
123
  }
124
-
125
- if ( $this->m_aOptions['enable_two_factor_auth_by_ip'] == 'Y' ) {
126
- // User has clicked a link in their email to validate their IP address for login.
127
- if ( isset( $_GET['wpsf-action'] ) && $_GET['wpsf-action'] == 'linkauth' ) {
128
- $this->validateUserAuthLink();
129
- }
130
-
 
 
131
  // If their click was successful we give them a lovely message
132
- if ( isset( $_GET['wpsfipverified']) ) {
133
  add_filter( 'login_message', array( $this, 'displayVerifiedUserMessage_Filter' ) );
134
  }
135
-
136
  // Check the current logged-in user every page load.
137
  add_action( 'init', array( $this, 'checkCurrentUserAuth_Action' ) );
138
-
139
- // At this stage (30,3) WordPress has already authenticated the user. So if the login
140
  // is valid, the filter will have a valid WP_User object passed to it.
141
  add_filter( 'authenticate', array( $this, 'checkUserAuthLogin_Filter' ), 30, 3);
142
  }
143
  }
144
-
 
 
145
  public function printGaspLoginCheck_Action() {
146
  echo $this->getGaspLoginHtml();
147
  }
148
-
 
 
 
149
  public function printGaspLoginCheck_Filter() {
150
  return $this->getGaspLoginHtml();
151
  }
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  public function checkLoginForGasp_Filter( $inoUser, $insUsername, $insPassword ) {
154
-
155
  if ( empty( $insUsername ) || is_wp_error( $inoUser ) ) {
156
  return $inoUser;
157
  }
158
  if ( $this->doGaspChecks( $insUsername ) ) {
159
  return $inoUser;
160
  }
161
- return null;
 
162
  }
163
-
164
  /**
165
  * Checks whether the current user that is logged-in is authenticated by IP address.
166
  *
@@ -169,14 +271,20 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
169
  * Should be hooked to 'init' so we have is_user_logged_in()
170
  */
171
  public function checkCurrentUserAuth_Action() {
 
 
 
 
 
 
172
  if ( is_user_logged_in() ) {
173
  $this->verifyCurrentUser();
174
  }
175
  }
176
 
177
  public function displayVerifiedUserMessage_Filter( $insMessage ) {
178
- $sStyles .= 'background-color: #FAFFE8; border: 1px solid #DDDDDD; margin: 8px 0 10px 8px; padding: 16px;';
179
- $insMessage .= '<h3 style="'.$sStyles.'">You successfully verified your IP address - you may now login.</h3>';
180
  return $insMessage;
181
  }
182
 
@@ -184,7 +292,7 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
184
  * Should return false when logging is disabled.
185
  *
186
  * @return false|array - false when logging is disabled, array with log data otherwise
187
- * @see ICWP_BaseProcessor_WPSF::getLogData()
188
  */
189
  public function flushLogData() {
190
 
@@ -202,36 +310,40 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
202
 
203
  /**
204
  * Checks the link details to ensure all is valid before authorizing the user.
205
- *
206
- * @return boolean
207
  */
208
  public function validateUserAuthLink() {
 
209
  // wpsfkey=%s&wpsf-action=%s&username=%s&uniqueid
210
-
211
- if ( !isset( $_GET['wpsfkey'] ) || $_GET['wpsfkey'] !== $this->m_sSecretKey ) {
212
  return false;
213
  }
214
- if ( empty( $_GET['username'] ) || empty( $_GET['uniqueid'] ) ) {
 
 
 
215
  return false;
216
  }
217
 
218
  $aWhere = array(
219
- 'unique_id' => $_GET['uniqueid'],
220
- 'wp_username' => $_GET['username']
221
  );
222
-
223
- if ( $this->loginAuthMakeActive( $aWhere ) ) {
224
- $this->redirectToLogin( '?wpsfipverified=1' );
 
 
 
 
 
 
225
  }
226
  else {
227
- header( "Location: ".home_url() );
228
  }
229
  }
230
-
231
- public function redirectToLogin( $sParams = '' ) {
232
- header( "Location: ".site_url().'/wp-login.php'.$sParams );
233
- }
234
-
235
  // WordPress Hooks and Filters:
236
 
237
  /**
@@ -244,13 +356,13 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
244
  * @return unknown|WP_Error
245
  */
246
  public function checkLoginInterval_Filter( $inoUser, $insUsername, $insPassword ) {
247
-
248
  // No login attempt was made.
249
  if ( empty( $insUsername ) ) {
250
  return $inoUser;
251
  }
252
 
253
  // Is there an interval set?
 
254
  $nRequiredLoginInterval = $this->m_nRequiredLoginInterval;
255
  if ( $nRequiredLoginInterval === false || $nRequiredLoginInterval == 0 ) {
256
  return $inoUser;
@@ -269,42 +381,168 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
269
  $nLoginInterval = $sNow - $this->m_nLastLoginTime;
270
  if ( $nLoginInterval > $nRequiredLoginInterval ) {
271
  $this->updateLastLoginThrottleTime( $sNow );
 
272
  return $inoUser;
273
  }
274
 
275
  // At this point someone has attempted to login within the previous login wait interval
276
  // So we remove WordPress's authentication filter and our own user check authentication
277
  // And finally return a WP_Error which will be reflected back to the user.
 
278
  remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 ); // wp-includes/user.php
279
  remove_filter( 'authenticate', array( $this, 'checkUserAuthLogin_Filter' ), 30, 3);
280
 
281
- $sErrorString = sprintf( "Sorry, you must wait %s seconds before attempting to login again.", ($nRequiredLoginInterval - $nLoginInterval ) );
282
  $oError = new WP_Error( 'wpsf_logininterval', $sErrorString );
283
  return $oError;
284
  }
285
-
 
 
 
286
  protected function getLastLoginTime() {
287
-
288
  // Check that there is a login throttle file. If it exists and its modified time is greater than the
289
  // current $this->m_nLastLoginTime it suggests another process has touched the file and updated it
290
  // concurrently. So, we update our $this->m_nEmailThrottleTime accordingly.
291
- if ( is_file( self::$sModeFile_LoginThrottled ) ) {
292
  $nModifiedTime = filemtime( self::$sModeFile_LoginThrottled );
293
  if ( $nModifiedTime > $this->m_nLastLoginTime ) {
294
  $this->m_nLastLoginTime = $nModifiedTime;
295
  }
296
  }
 
297
  return $this->m_nLastLoginTime;
298
  }
299
-
 
 
 
300
  public function updateLastLoginThrottleTime( $innLastLoginTime ) {
 
301
  $this->m_nLastLoginTime = $innLastLoginTime;
302
- if ( function_exists('touch') ) {
303
- @touch( self::$sModeFile_LoginThrottled, $innLastLoginTime );
304
- }
305
  $this->setNeedSave();
306
  }
307
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  /**
309
  * If $inoUser is a valid WP_User object, then the user logged in correctly.
310
  *
@@ -320,7 +558,7 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
320
  * 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.
321
  * c) note at this stage, if the username was empty, we give back nothing (this happens when wp-login.php is loaded as normal.
322
  *
323
- * @param WP_User|string $inmUser - the docs say the first parameter a string, WP actually gives a WP_User object (or null)
324
  * @param string $insUsername
325
  * @param string $insPassword
326
  * @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.
@@ -340,22 +578,26 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
340
  }
341
  }
342
  else if ( $fUserLoginSuccess ) {
343
-
344
- $aData = array( 'wp_username' => $insUsername );
345
- if ( $this->isUserVerified( $aData ) ) {
 
 
 
346
  return $inoUser;
347
  }
348
  else {
349
  // Create a new 2-factor auth pending entry
350
- $aNewAuthData = $this->loginAuthAddPending( array( 'wp_username' => $inoUser->user_login ) );
351
 
352
  // Now send email with authentication link for user.
353
  if ( is_array( $aNewAuthData ) ) {
 
354
  $fEmailSuccess = $this->sendEmailTwoFactorVerify( $inoUser, $aNewAuthData['ip'], $aNewAuthData['unique_id'] );
355
 
356
  // Failure to send email - log them in.
357
  if ( !$fEmailSuccess && $this->getTwoFactorByPassOnFail() ) {
358
- $this->loginAuthMakeActive( $aNewAuthData );
359
  return $inoUser;
360
  }
361
  }
@@ -365,11 +607,40 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
365
  $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.";
366
  return new WP_Error( 'wpsf_loginauth', $sErrorString );
367
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
 
369
  public function getGaspLoginHtml() {
370
 
371
- $sLabel = "I'm a human.";
372
- $sAlert = "Please check the box to show us you're a human.";
373
 
374
  $sUniqElem = 'icwp_wpsf_login_p'.uniqid();
375
 
@@ -411,7 +682,7 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
411
  return true;
412
  }
413
  </script>
414
- <noscript>You MUST enable Javascript to be able to login</noscript>
415
  <input type="hidden" id="icwp_wpsf_login_email" name="icwp_wpsf_login_email" value="" />
416
  ';
417
 
@@ -428,23 +699,25 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
428
  public function doGaspChecks( $insUsername ) {
429
  if ( !isset( $_POST[ $this->getGaspCheckboxName() ] ) ) {
430
  $this->logWarning(
431
- sprintf( 'User "%s" attempted to login but GASP checkbox was not present. Bot Perhaps? IP Address: "%s".', $insUsername, long2ip($this->m_nRequestIp) )
432
  );
 
433
  wp_die( "You must check that box to say you're not a bot." );
434
  return false;
435
  }
436
  else if ( isset( $_POST['icwp_wpsf_login_email'] ) && $_POST['icwp_wpsf_login_email'] !== '' ){
437
  $this->logWarning(
438
- sprintf( 'User "%s" attempted to login but they were caught by the GASP honey pot. Bot Perhaps? IP Address: "%s".', $insUsername, long2ip($this->m_nRequestIp) )
439
  );
440
- wp_die( 'You smell like a bot.' );
 
441
  return false;
442
  }
443
  return true;
444
  }
445
 
446
  public function setTwoFactorByPassOnFail() {
447
- $this->m_fAllowTwoFactorByPass = $this->m_aOptions[ 'enable_two_factor_bypass_on_email_fail' ] == 'Y';
448
  }
449
 
450
  public function getTwoFactorByPassOnFail() {
@@ -453,20 +726,21 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
453
  }
454
  return $this->m_fAllowTwoFactorByPass;
455
  }
456
-
 
 
457
  public function setLoginCooldownInterval() {
458
- $nInterval = intval( $this->m_aOptions[ 'login_limit_interval' ] );
459
  $this->m_nRequiredLoginInterval = ( $nInterval < 0 )? 0 : $nInterval;
460
  }
461
 
462
  /**
463
- * @param array $inaData
464
  * @return boolean
465
  */
466
- public function loginAuthAddPending( $inaData ) {
467
 
468
- $aChecks = array( 'wp_username' );
469
- if ( !$this->validateParameters( $inaData, $aChecks) ) {
470
  return false;
471
  }
472
 
@@ -480,23 +754,25 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
480
  $aOldWhere = array(
481
  'pending' => 1,
482
  'deleted_at' => 0,
483
- 'wp_username' => $inaData[ 'wp_username' ]
484
  );
485
  $this->updateRowsFromTable( $aOldData, $aOldWhere );
486
 
487
  // Now add new pending entry
488
- $inaData[ 'unique_id' ] = uniqid();
489
- $inaData[ 'ip_long' ] = $this->m_nRequestIp;
490
- $inaData[ 'ip' ] = long2ip( $this->m_nRequestIp );
491
- $inaData[ 'pending' ] = 1;
492
- $inaData[ 'created_at' ] = time();
 
 
493
 
494
- $mResult = $this->insertIntoTable( $inaData );
495
  if ( $mResult ) {
496
  $this->logInfo(
497
- sprintf( 'User "%s" created a pending Two-Factor Authentication for IP Address "%s".', $inaData[ 'wp_username' ], $inaData[ 'ip' ] )
498
  );
499
- $mResult = $inaData;
500
  }
501
  return $mResult;
502
  }
@@ -507,16 +783,57 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
507
  * @param array $inaWhere - unique_id, wp_username
508
  * @return boolean
509
  */
510
- public function loginAuthMakeActive( $inaWhere ) {
511
 
512
  $aChecks = array( 'unique_id', 'wp_username' );
513
  if ( !$this->validateParameters( $inaWhere, $aChecks ) ) {
514
  return false;
515
  }
516
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
517
  $sNow = time();
518
-
519
- // First set any active, non-pending entries for the given user to be deleted.
520
  $sQuery = "
521
  UPDATE `%s`
522
  SET `deleted_at` = '%s',
@@ -530,75 +847,109 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
530
  $this->m_sTableName,
531
  $sNow,
532
  $sNow,
533
- $inaWhere['wp_username']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534
  );
535
  $this->doSql( $sQuery );
536
-
537
- $inaWhere['pending'] = 1;
538
- $inaWhere['deleted_at'] = 0;
539
-
540
- // Now activate the new one.
541
- $mResult = $this->updateRowsFromTable( array( 'pending' => 0 ), $inaWhere );
542
- if ( $mResult ) {
543
- $this->logInfo(
544
- sprintf( 'User "%s" has verified their IP Address using Two-Factor Authentication.', $inaWhere[ 'wp_username' ] )
545
- );
546
- }
547
- return $mResult;
548
  }
549
 
550
  /**
551
  * Checks whether a given user is authenticated.
552
  *
553
- * @param array $inaWhere
554
  * @return boolean
555
  */
556
- public function isUserVerified( $inaWhere ) {
557
-
558
- $aChecks = array( 'wp_username' );
559
- if ( !$this->validateParameters( $inaWhere, $aChecks ) ) {
560
- return false;
561
- }
562
-
563
  $sQuery = "
564
  SELECT *
565
  FROM `%s`
566
  WHERE
567
  `wp_username` = '%s'
568
- AND `ip_long` = '%s'
569
  AND `pending` = '0'
570
  AND `deleted_at` = '0'
571
  AND `expired_at` = '0'
572
  ";
 
573
  $sQuery = sprintf( $sQuery,
574
  $this->m_sTableName,
575
- $inaWhere['wp_username'],
576
- $this->m_nRequestIp
577
  );
578
 
579
  $mResult = $this->selectCustomFromTable( $sQuery );
 
580
  if ( is_array( $mResult ) && count( $mResult ) == 1 ) {
581
- return true;
 
 
 
 
 
 
 
 
 
582
  }
583
  else {
584
  $this->logWarning(
585
- sprintf( 'User "%s" was found to be un-verified at this given IP Address "%s".', $inaWhere[ 'wp_username' ], long2ip( $this->m_nRequestIp ) )
586
  );
587
  return false;
588
  }
589
  }
590
-
 
 
 
 
 
 
 
 
 
 
 
 
591
  public function verifyCurrentUser() {
592
  $oUser = wp_get_current_user();
593
  if ( is_object( $oUser ) && $oUser instanceof WP_User ) {
594
 
595
- $aData = array( 'wp_username' => $oUser->user_login );
596
- if ( !$this->isUserVerified( $aData ) ) {
597
  $this->logWarning(
598
- sprintf( 'User "%s" was logged out.', $oUser->user_login )
599
  );
 
600
  wp_logout();
601
- $this->redirectToLogin();
 
602
  }
603
  }
604
  }
@@ -606,49 +957,62 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
606
  /**
607
  * Given the necessary components, creates the 2-factor verification link for giving to the user.
608
  *
609
- * @param string $insKey
610
- * @param string $insUser
611
- * @param string $insUniqueId
612
  * @return string
613
  */
614
- public function getTwoFactorVerifyLink( $insKey, $insUser, $insUniqueId ) {
615
  $sSiteUrl = home_url() . '?wpsfkey=%s&wpsf-action=%s&username=%s&uniqueid=%s';
616
  $sAction = 'linkauth';
617
- return sprintf( $sSiteUrl, $insKey, $sAction, $insUser, $insUniqueId );
618
  }
619
 
620
  /**
621
- * @param string $sEmail
622
  * @param string $insIpAddress
623
- * @param string $insAuthLink
 
624
  */
625
  public function sendEmailTwoFactorVerify( WP_User $inoUser, $insIpAddress, $insUniqueId ) {
626
 
627
  $sEmail = $inoUser->user_email;
628
- $sAuthLink = $this->getTwoFactorVerifyLink( $this->m_sSecretKey, $inoUser->user_login, $insUniqueId );
629
 
630
  $aMessage = array(
631
- 'You, or someone pretending to be you, just attempted to login into your WordPress site.',
632
- 'The IP Address from which they tried to login is not currently valid.',
633
- 'To validate this address, click the following link, and then login again.',
634
- 'IP Address: '. $insIpAddress,
635
- 'Authentication Link: '. $sAuthLink
636
  );
637
- $sEmailSubject = 'Two-Factor Login Verification: ' . home_url();
638
-
 
 
 
639
  $fResult = $this->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
640
  if ( $fResult ) {
641
  $this->logInfo(
642
- sprintf( 'User "%s" was sent an email to verify their Two-Factor Login for IP Address "%s".', $inoUser->user_login, $insIpAddress )
643
  );
644
  }
645
  else {
646
  $this->logCritical(
647
- sprintf( 'Tried to send User "%s" email to verify their Two-Factor Login for IP Address "%s", but email sending failed.', $inoUser->user_login, $insIpAddress )
648
  );
649
  }
650
  return $fResult;
651
  }
 
 
 
 
 
 
 
 
 
 
652
 
653
  public function createTable() {
654
 
@@ -681,6 +1045,40 @@ class ICWP_LoginProtectProcessor extends ICWP_BaseDbProcessor_WPSF {
681
  $sQuery = sprintf( $sQuery, $this->m_sTableName, $inaData['unique_id'], $inaData['wp_username'] );
682
  return $this->selectRowFromTable( $sQuery );
683
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
684
  }
 
685
 
 
 
686
  endif;
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
17
 
18
  require_once( dirname(__FILE__).'/icwp-basedb-processor.php' );
19
 
20
+ if ( !class_exists('ICWP_LoginProtectProcessor_V2') ):
21
 
22
+ class ICWP_LoginProtectProcessor_V2 extends ICWP_BaseDbProcessor_WPSF {
23
 
24
+ const Slug = 'login_protect';
25
  const TableName = 'login_auth';
26
+ const AuthActiveCookie = 'wpsf_auth';
27
+ const YubikeyVerifyApiUrl = 'https://api.yubico.com/wsapi/2.0/verify?id=%s&otp=%s&nonce=%s';
28
+
29
  /**
30
  * @var string
31
  */
36
  * @var integer
37
  */
38
  protected $m_nRequiredLoginInterval;
39
+
40
+ /**
41
+ * @var integer
42
+ */
43
  protected $m_nLastLoginTime;
44
+ /**
45
+ * @var string
46
+ */
47
  protected $m_sSecretKey;
48
+ /**
49
+ * @var string
50
+ */
51
  protected $m_sGaspKey;
52
+ /**
53
+ * @var string
54
+ */
55
+ protected $nDaysToKeepLog = 1;
56
 
57
  /**
58
  * Flag as to whether Two Factor Authentication will be by-pass when sending the verification
61
  * @var boolean
62
  */
63
  protected $m_fAllowTwoFactorByPass;
 
 
 
64
 
65
+ public function __construct( $insOptionPrefix = '' ) {
66
+ parent::__construct( $this->constructStorageKey( $insOptionPrefix, self::Slug ), self::TableName );
67
  $this->m_sGaspKey = uniqid();
 
68
  $this->updateLastLoginThrottleTime( time() );
 
69
  $this->createTable();
70
  $this->reset();
71
  }
75
  */
76
  public function reset() {
77
  parent::reset();
78
+ self::$sModeFile_LoginThrottled = dirname( __FILE__ ).'/../mode.login_throttled';
79
+ $this->genSecretKey();
80
+ }
81
+
82
+ /**
83
+ * Set the secret key by which authentication is validated.
84
+ *
85
+ * @param boolean $infForceUpdate
86
+ * @return string
87
+ */
88
+ public function genSecretKey( $infForceUpdate = false ) {
89
+ if ( empty( $this->m_sSecretKey ) || $infForceUpdate ) {
90
+ $this->m_sSecretKey = md5( mt_rand() );
91
+ }
92
+ return $this->m_sSecretKey;
93
  }
94
 
95
  /**
99
  */
100
  public function setSecretKey( $insSecretKey = '' ) {
101
  if ( !empty( $insSecretKey ) ) {
102
+ $this->genSecretKey();
103
+ }
104
+ else {
105
  $this->m_sSecretKey = $insSecretKey;
106
  }
107
  }
108
 
109
  /**
110
  *
111
+ * @param array $inaOptions
112
  */
113
  public function setOptions( &$inaOptions ) {
114
  parent::setOptions( $inaOptions );
121
  * @return boolean
122
  */
123
  public function getNeedsEmailHandler() {
124
+ return $this->getIsTwoFactorAuthOn();
125
+ }
126
+
127
+ /**
128
+ * @param string $sType can be either 'ip' or 'cookie'. If empty, both are checked looking for either.
129
+ * @return bool
130
+ */
131
+ protected function getIsTwoFactorAuthOn( $sType = '' ) {
132
+
133
+ $fIp = $this->getOption( 'enable_two_factor_auth_by_ip', 'N' ) == 'Y';
134
+ $fCookie = $this->getOption( 'enable_two_factor_auth_by_cookie', 'N' ) == 'Y';
135
+
136
+ switch( $sType ) {
137
+ case 'ip':
138
+ return $fIp;
139
+ break;
140
+ case 'cookie':
141
+ return $fCookie;
142
+ break;
143
+ default:
144
+ return $fIp || $fCookie;
145
+ break;
146
  }
 
147
  }
148
 
149
+ public function setLogging( $infEnableLogging = true ) {
150
+ parent::setLogging( $this->getOption('enable_login_protect_log') == 'Y' );
151
  }
152
 
153
  /**
 
154
  */
155
  public function run() {
156
+ parent::run();
157
+ $this->loadDataProcessor();
158
+ // $this->recreateTable();
159
+
160
+ $sRequestMethod = ICWP_WPSF_DataProcessor::ArrayFetch( $_SERVER, 'REQUEST_METHOD' );
161
+ $fIsPost = strtolower( empty($sRequestMethod)? '' : $sRequestMethod ) == 'post';
162
+
163
+ $aWhitelist = $this->getOption( 'ips_whitelist', array() );
164
  if ( !empty( $aWhitelist ) && $this->isIpOnlist( $aWhitelist, self::GetVisitorIpAddress() ) ) {
165
  return true;
166
  }
167
+
168
+ // check for remote posting before anything else.
169
+ if ( $fIsPost && $this->getIsOption('enable_prevent_remote_post', 'Y') ) {
170
+ add_filter( 'authenticate', array( $this, 'checkRemotePostLogin_Filter' ), 9, 3);
171
+ }
172
+
173
  // Add GASP checking to the login form.
174
+ if ( $this->getIsOption('enable_login_gasp_check', 'Y') ) {
175
  add_action( 'login_form', array( $this, 'printGaspLoginCheck_Action' ) );
176
  add_filter( 'login_form_middle', array( $this, 'printGaspLoginCheck_Filter' ) );
177
+ add_filter( 'authenticate', array( $this, 'checkLoginForGasp_Filter' ), 22, 3);
178
+ // add_action( 'woocommerce_login_form', array( $this, 'printGaspLoginCheck_Action' ) );
179
  }
180
 
181
+ // Do GASP checking if it's a form submit.
182
+ if ( $fIsPost && $this->getOption( 'login_limit_interval' ) > 0 ) {
183
  // We give it a priority of 10 so that we can jump in before WordPress does its own validation.
184
  add_filter( 'authenticate', array( $this, 'checkLoginInterval_Filter' ), 10, 3);
185
  }
186
+
187
+ // check for Yubikey auth after user is authenticated with WordPress.
188
+ if ( $fIsPost && $this->getOption('enable_yubikey') && $this->getIsYubikeyConfigReady() ) {
189
+ add_filter( 'wp_authenticate_user', array( $this, 'checkYubikeyOtpAuth_Filter' ) );
190
+ add_action( 'login_form', array( $this, 'printYubikeyOtp_Action' ) );
191
+ }
192
+
193
+ if ( $this->getIsTwoFactorAuthOn() ) {
194
+
195
  // If their click was successful we give them a lovely message
196
+ if ( ICWP_WPSF_DataProcessor::FetchGet( 'wpsfuserverified' ) ) {
197
  add_filter( 'login_message', array( $this, 'displayVerifiedUserMessage_Filter' ) );
198
  }
199
+
200
  // Check the current logged-in user every page load.
201
  add_action( 'init', array( $this, 'checkCurrentUserAuth_Action' ) );
202
+
203
+ // At this stage (30,3) WordPress has already (20) authenticated the user. So if the login
204
  // is valid, the filter will have a valid WP_User object passed to it.
205
  add_filter( 'authenticate', array( $this, 'checkUserAuthLogin_Filter' ), 30, 3);
206
  }
207
  }
208
+
209
+ /**
210
+ */
211
  public function printGaspLoginCheck_Action() {
212
  echo $this->getGaspLoginHtml();
213
  }
214
+
215
+ /**
216
+ * @return string
217
+ */
218
  public function printGaspLoginCheck_Filter() {
219
  return $this->getGaspLoginHtml();
220
  }
221
 
222
+ /**
223
+ * @param $inoUser
224
+ * @param $insUsername
225
+ * @param $insPassword
226
+ * @return mixed
227
+ */
228
+ public function checkRemotePostLogin_Filter( $inoUser, $insUsername, $insPassword ) {
229
+ $this->loadDataProcessor();
230
+ $sHttpRef = ICWP_WPSF_DataProcessor::ArrayFetch( $_SERVER, 'HTTP_REFERER' );
231
+ $sHttpRef = is_null( $sHttpRef )? '' : $sHttpRef;
232
+ if ( empty($sHttpRef) || ( strpos($sHttpRef, home_url()) !== 0 ) ) {
233
+ $this->logWarning(
234
+ 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 )
235
+ );
236
+ $this->doStatIncrement( 'login.remotepost.fail' );
237
+ wp_die(
238
+ _wpsf__( 'Sorry, you must login directly from within the site.' )
239
+ .'<br /><a href="http://icwp.io/4n" target="_blank">&rarr;'._wpsf__('More Info').'</a>'
240
+ );
241
+ }
242
+ else {
243
+ $this->doStatIncrement( 'login.remotepost.success' );
244
+ }
245
+ return $inoUser;
246
+ }
247
+
248
+ /**
249
+ * @param $inoUser
250
+ * @param $insUsername
251
+ * @param $insPassword
252
+ * @return WP_Error
253
+ */
254
  public function checkLoginForGasp_Filter( $inoUser, $insUsername, $insPassword ) {
255
+
256
  if ( empty( $insUsername ) || is_wp_error( $inoUser ) ) {
257
  return $inoUser;
258
  }
259
  if ( $this->doGaspChecks( $insUsername ) ) {
260
  return $inoUser;
261
  }
262
+ //This doesn't actually ever get returned because we die() within doGaspChecks()
263
+ return new WP_Error('wpsf_gaspfail', _wpsf__('G.A.S.P. Checking Failed.') );
264
  }
265
+
266
  /**
267
  * Checks whether the current user that is logged-in is authenticated by IP address.
268
  *
271
  * Should be hooked to 'init' so we have is_user_logged_in()
272
  */
273
  public function checkCurrentUserAuth_Action() {
274
+
275
+ // User has clicked a link in their email to validate their IP address for login.
276
+ if ( ICWP_WPSF_DataProcessor::FetchGet( 'wpsf-action' ) == 'linkauth' ) {
277
+ $this->validateUserAuthLink();
278
+ }
279
+
280
  if ( is_user_logged_in() ) {
281
  $this->verifyCurrentUser();
282
  }
283
  }
284
 
285
  public function displayVerifiedUserMessage_Filter( $insMessage ) {
286
+ $sStyles = 'background-color: #FAFFE8; border: 1px solid #DDDDDD; margin: 8px 0 10px 8px; padding: 16px;';
287
+ $insMessage .= '<h3 style="'.$sStyles.'">'._wpsf__('You have successfully verified your identity - you may now login').'</h3>';
288
  return $insMessage;
289
  }
290
 
292
  * Should return false when logging is disabled.
293
  *
294
  * @return false|array - false when logging is disabled, array with log data otherwise
295
+ * @see ICWP_WPSF_BaseProcessor::getLogData()
296
  */
297
  public function flushLogData() {
298
 
310
 
311
  /**
312
  * Checks the link details to ensure all is valid before authorizing the user.
 
 
313
  */
314
  public function validateUserAuthLink() {
315
+ $this->loadDataProcessor();
316
  // wpsfkey=%s&wpsf-action=%s&username=%s&uniqueid
317
+
318
+ if ( ICWP_WPSF_DataProcessor::FetchGet( 'wpsfkey' ) !== $this->m_sSecretKey ) {
319
  return false;
320
  }
321
+
322
+ $sUsername = ICWP_WPSF_DataProcessor::FetchGet( 'username' );
323
+ $sUniqueId = ICWP_WPSF_DataProcessor::FetchGet( 'uniqueid' );
324
+ if ( empty( $sUsername ) || empty( $sUniqueId ) ) {
325
  return false;
326
  }
327
 
328
  $aWhere = array(
329
+ 'unique_id' => $sUniqueId,
330
+ 'wp_username' => $sUsername
331
  );
332
+
333
+ $oWp = $this->loadWpFunctionsProcessor();
334
+ if ( $this->doMakePendingLoginAuthActive( $aWhere ) ) {
335
+ $this->logInfo(
336
+ sprintf( _wpsf__('User "%s" verified their identity using Two-Factor Authentication.'), $sUsername )
337
+ );
338
+ $this->setUserLoggedIn( $sUsername );
339
+ $this->doStatIncrement( 'login.twofactor.verified' );
340
+ $oWp->redirectToAdmin();
341
  }
342
  else {
343
+ $oWp->redirectToHome();
344
  }
345
  }
346
+
 
 
 
 
347
  // WordPress Hooks and Filters:
348
 
349
  /**
356
  * @return unknown|WP_Error
357
  */
358
  public function checkLoginInterval_Filter( $inoUser, $insUsername, $insPassword ) {
 
359
  // No login attempt was made.
360
  if ( empty( $insUsername ) ) {
361
  return $inoUser;
362
  }
363
 
364
  // Is there an interval set?
365
+ $this->setLoginCooldownInterval();
366
  $nRequiredLoginInterval = $this->m_nRequiredLoginInterval;
367
  if ( $nRequiredLoginInterval === false || $nRequiredLoginInterval == 0 ) {
368
  return $inoUser;
381
  $nLoginInterval = $sNow - $this->m_nLastLoginTime;
382
  if ( $nLoginInterval > $nRequiredLoginInterval ) {
383
  $this->updateLastLoginThrottleTime( $sNow );
384
+ $this->doStatIncrement( 'login.cooldown.success' );
385
  return $inoUser;
386
  }
387
 
388
  // At this point someone has attempted to login within the previous login wait interval
389
  // So we remove WordPress's authentication filter and our own user check authentication
390
  // And finally return a WP_Error which will be reflected back to the user.
391
+ $this->doStatIncrement( 'login.cooldown.fail' );
392
  remove_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 ); // wp-includes/user.php
393
  remove_filter( 'authenticate', array( $this, 'checkUserAuthLogin_Filter' ), 30, 3);
394
 
395
+ $sErrorString = sprintf( _wpsf__( "Login Cooldown in effect. You must wait %s seconds before attempting to login again." ), ($nRequiredLoginInterval - $nLoginInterval ) );
396
  $oError = new WP_Error( 'wpsf_logininterval', $sErrorString );
397
  return $oError;
398
  }
399
+
400
+ /**
401
+ * @return int
402
+ */
403
  protected function getLastLoginTime() {
404
+ $oWpFs = $this->loadFileSystemProcessor();
405
  // Check that there is a login throttle file. If it exists and its modified time is greater than the
406
  // current $this->m_nLastLoginTime it suggests another process has touched the file and updated it
407
  // concurrently. So, we update our $this->m_nEmailThrottleTime accordingly.
408
+ if ( $oWpFs->fileAction( 'file_exists', self::$sModeFile_LoginThrottled ) ) {
409
  $nModifiedTime = filemtime( self::$sModeFile_LoginThrottled );
410
  if ( $nModifiedTime > $this->m_nLastLoginTime ) {
411
  $this->m_nLastLoginTime = $nModifiedTime;
412
  }
413
  }
414
+ else { }
415
  return $this->m_nLastLoginTime;
416
  }
417
+
418
+ /**
419
+ * @param $innLastLoginTime
420
+ */
421
  public function updateLastLoginThrottleTime( $innLastLoginTime ) {
422
+ $oWpFs = $this->loadFileSystemProcessor();
423
  $this->m_nLastLoginTime = $innLastLoginTime;
424
+ $oWpFs->fileAction( 'touch', array(self::$sModeFile_LoginThrottled, $innLastLoginTime) );
 
 
425
  $this->setNeedSave();
426
  }
427
 
428
+ /**
429
+ */
430
+ public function printYubikeyOtp_Action() {
431
+ $sHtml =
432
+ '<p class="yubikey-otp">
433
+ <label>%s<br />
434
+ <input type="text" name="yubiotp" class="input" value="" size="20" />
435
+ </label>
436
+ </p>
437
+ ';
438
+ echo sprintf( $sHtml, '<a href="http://icwp.io/4i" target="_blank">'._wpsf__('Yubikey OTP').'</a>' );
439
+ }
440
+
441
+ /**
442
+ * @param WP_User $inoUser
443
+ * @return WP_User|WP_Error
444
+ */
445
+ public function checkYubikeyOtpAuth_Filter( $inoUser ) {
446
+ $oError = new WP_Error();
447
+
448
+ // Before anything else we check that a Yubikey pair has been provided for this username (and that there are pairs in the first place!)
449
+ $aYubikeyUsernamePairs = $this->getOption('yubikey_unique_keys');
450
+ if ( !$this->getIsYubikeyConfigReady() ) { // configuration is clearly not completed yet.
451
+ return $inoUser;
452
+ }
453
+
454
+ $sOneTimePassword = empty( $_POST['yubiotp'] )? '' : trim( $_POST['yubiotp'] );
455
+ $sAppId = $this->getOption('yubikey_app_id');
456
+ $sApiKey = $this->getOption('yubikey_api_key');
457
+
458
+ // check that if we have a list of permitted keys, that the one used is on that list connected with the username.
459
+ $sYubikey12 = substr( $sOneTimePassword, 0 , 12 );
460
+ $fUsernameFound = false; // if username is never found, it means there's no yubikey specified which means we can bypass this authentication method.
461
+ $fFoundMatch = false;
462
+ foreach( $aYubikeyUsernamePairs as $aUsernameYubikeyPair ) {
463
+ if ( isset( $aUsernameYubikeyPair[$inoUser->user_login] ) ) {
464
+ $fUsernameFound = true;
465
+ if ( $aUsernameYubikeyPair[$inoUser->user_login] == $sYubikey12 ) {
466
+ $fFoundMatch = true;
467
+ break;
468
+ }
469
+ }
470
+ }
471
+
472
+ // If no yubikey-username pair found for given username, we by-pass Yubikey auth.
473
+ if ( !$fUsernameFound ) {
474
+ $this->logWarning(
475
+ 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 )
476
+ );
477
+ return $inoUser;
478
+ }
479
+
480
+ // Username was found in the list of key pairs, but the yubikey provided didn't match that username.
481
+ if ( !$fFoundMatch ) {
482
+ $oError->add(
483
+ 'yubikey_not_allowed',
484
+ sprintf( _wpsf__( 'ERROR: %s' ), _wpsf__('The Yubikey provided is not on the list of permitted keys for this user.') )
485
+ );
486
+ $this->logWarning(
487
+ sprintf( _wpsf__('User "%s" attempted to login but Yubikey ID used was not in list of authorised keys: "%s".'), $inoUser->user_login, $sYubikey12 )
488
+ );
489
+ return $oError;
490
+ }
491
+
492
+ $oFs = $this->loadFileSystemProcessor();
493
+
494
+ $sNonce = md5( uniqid( rand() ) );
495
+ $sUrl = sprintf( self::YubikeyVerifyApiUrl, $sAppId, $sOneTimePassword, $sNonce );
496
+ $sRawYubiRequest = $oFs->getUrlContent( $sUrl );
497
+
498
+ // Validate response.
499
+ // 1. Check OTP and Nonce
500
+ if ( !preg_match( '/otp='.$sOneTimePassword.'/', $sRawYubiRequest, $aMatches )
501
+ || !preg_match( '/nonce='.$sNonce.'/', $sRawYubiRequest, $aMatches )
502
+ ) {
503
+ $oError->add(
504
+ 'yubikey_validate_fail',
505
+ sprintf( _wpsf__( 'ERROR: %s' ), _wpsf__('The Yubikey authentication was not validated successfully.') )
506
+ );
507
+ $this->logWarning(
508
+ sprintf( _wpsf__('User "%s" attempted to login but Yubikey One Time Password failed to validate due to invalid Yubi API.'), $inoUser->user_login )
509
+ );
510
+ return $oError;
511
+ }
512
+
513
+ // Optionally we can check the hash, but since we're using HTTPS, this isn't necessary and adds more PHP requirements
514
+
515
+ // 2. Check status directly within response
516
+ preg_match( '/status=([a-zA-Z0-9_]+)/', $sRawYubiRequest, $aMatches );
517
+ $sStatus = $aMatches[1];
518
+
519
+ if ( $sStatus != 'OK' && $sStatus != 'REPLAYED_OTP' ) {
520
+ $oError->add(
521
+ 'yubikey_validate_fail',
522
+ sprintf( _wpsf__( 'ERROR: %s' ), _wpsf__('The Yubikey authentication was not validated successfully.') )
523
+ );
524
+ $this->logWarning(
525
+ 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 )
526
+ );
527
+ return $oError;
528
+ }
529
+
530
+ $this->logInfo(
531
+ sprintf( _wpsf__('User "%s" successfully logged in using a validated Yubikey One Time Password.'), $inoUser->user_login )
532
+ );
533
+ return $inoUser;
534
+ }
535
+
536
+ /**
537
+ * @return bool
538
+ */
539
+ protected function getIsYubikeyConfigReady() {
540
+ $sAppId = $this->getOption('yubikey_app_id');
541
+ $sApiKey = $this->getOption('yubikey_api_key');
542
+ $aYubikeyKeys = $this->getOption('yubikey_unique_keys');
543
+ return !empty($sAppId) && !empty($sApiKey) && !empty($aYubikeyKeys);
544
+ }
545
+
546
  /**
547
  * If $inoUser is a valid WP_User object, then the user logged in correctly.
548
  *
558
  * 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.
559
  * c) note at this stage, if the username was empty, we give back nothing (this happens when wp-login.php is loaded as normal.
560
  *
561
+ * @param WP_User|string $inoUser - the docs say the first parameter a string, WP actually gives a WP_User object (or null)
562
  * @param string $insUsername
563
  * @param string $insPassword
564
  * @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.
578
  }
579
  }
580
  else if ( $fUserLoginSuccess ) {
581
+
582
+ if ( !$this->getIsUserLevelSubjectToTwoFactorAuth( $inoUser->user_level ) ) {
583
+ return $inoUser;
584
+ }
585
+
586
+ if ( $this->isUserVerified( $insUsername ) ) {
587
  return $inoUser;
588
  }
589
  else {
590
  // Create a new 2-factor auth pending entry
591
+ $aNewAuthData = $this->addNewPendingLoginAuth( $inoUser->user_login );
592
 
593
  // Now send email with authentication link for user.
594
  if ( is_array( $aNewAuthData ) ) {
595
+ $this->doStatIncrement( 'login.twofactor.started' );
596
  $fEmailSuccess = $this->sendEmailTwoFactorVerify( $inoUser, $aNewAuthData['ip'], $aNewAuthData['unique_id'] );
597
 
598
  // Failure to send email - log them in.
599
  if ( !$fEmailSuccess && $this->getTwoFactorByPassOnFail() ) {
600
+ $this->doMakePendingLoginAuthActive( $aNewAuthData );
601
  return $inoUser;
602
  }
603
  }
607
  $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.";
608
  return new WP_Error( 'wpsf_loginauth', $sErrorString );
609
  }
610
+
611
+ /**
612
+ * TODO: http://stackoverflow.com/questions/3499104/how-to-know-the-role-of-current-user-in-wordpress
613
+ * @param integer $nUserLevel
614
+ * @return bool
615
+ */
616
+ public function getIsUserLevelSubjectToTwoFactorAuth( $nUserLevel ) {
617
+
618
+ $aSubjectedUserLevels = $this->getOption( 'two_factor_auth_user_roles' );
619
+ if ( empty($aSubjectedUserLevels) || !is_array($aSubjectedUserLevels) ) {
620
+ $aSubjectedUserLevels = array( 1, 2, 3, 8 ); // by default all except subscribers!
621
+ }
622
+
623
+ // see: https://codex.wordpress.org/Roles_and_Capabilities#User_Level_to_Role_Conversion
624
+
625
+ // authors, contributors and subscribers
626
+ if ( $nUserLevel < 3 && in_array( $nUserLevel, $aSubjectedUserLevels ) ) {
627
+ return true;
628
+ }
629
+ // editors
630
+ if ( $nUserLevel >= 3 && $nUserLevel < 8 && in_array( 3, $aSubjectedUserLevels ) ) {
631
+ return true;
632
+ }
633
+ // administrators
634
+ if ( $nUserLevel >= 8 && $nUserLevel <= 10 && in_array( 8, $aSubjectedUserLevels ) ) {
635
+ return true;
636
+ }
637
+ return false;
638
+ }
639
 
640
  public function getGaspLoginHtml() {
641
 
642
+ $sLabel = _wpsf__("I'm a human.");
643
+ $sAlert = _wpsf__("Please check the box to show us you're a human.");
644
 
645
  $sUniqElem = 'icwp_wpsf_login_p'.uniqid();
646
 
682
  return true;
683
  }
684
  </script>
685
+ <noscript>'._wpsf__('You MUST enable Javascript to be able to login').'</noscript>
686
  <input type="hidden" id="icwp_wpsf_login_email" name="icwp_wpsf_login_email" value="" />
687
  ';
688
 
699
  public function doGaspChecks( $insUsername ) {
700
  if ( !isset( $_POST[ $this->getGaspCheckboxName() ] ) ) {
701
  $this->logWarning(
702
+ sprintf( _wpsf__('User "%s" attempted to login but GASP checkbox was not present. Bot Perhaps? IP Address: "%s".'), $insUsername, long2ip($this->m_nRequestIp) )
703
  );
704
+ $this->doStatIncrement( 'login.gasp.checkbox.fail' );
705
  wp_die( "You must check that box to say you're not a bot." );
706
  return false;
707
  }
708
  else if ( isset( $_POST['icwp_wpsf_login_email'] ) && $_POST['icwp_wpsf_login_email'] !== '' ){
709
  $this->logWarning(
710
+ sprintf( _wpsf__('User "%s" attempted to login but they were caught by the GASP honey pot. Bot Perhaps? IP Address: "%s".'), $insUsername, long2ip($this->m_nRequestIp) )
711
  );
712
+ $this->doStatIncrement( 'login.gasp.honeypot.fail' );
713
+ wp_die( _wpsf__('You appear to be a bot - terminating login attempt.') );
714
  return false;
715
  }
716
  return true;
717
  }
718
 
719
  public function setTwoFactorByPassOnFail() {
720
+ $this->m_fAllowTwoFactorByPass = $this->getIsOption( 'enable_two_factor_bypass_on_email_fail', 'Y' );
721
  }
722
 
723
  public function getTwoFactorByPassOnFail() {
726
  }
727
  return $this->m_fAllowTwoFactorByPass;
728
  }
729
+
730
+ /**
731
+ */
732
  public function setLoginCooldownInterval() {
733
+ $nInterval = intval( $this->getOption('login_limit_interval', 0) );
734
  $this->m_nRequiredLoginInterval = ( $nInterval < 0 )? 0 : $nInterval;
735
  }
736
 
737
  /**
738
+ * @param string $sUsername
739
  * @return boolean
740
  */
741
+ public function addNewPendingLoginAuth( $sUsername ) {
742
 
743
+ if ( empty( $sUsername ) ) {
 
744
  return false;
745
  }
746
 
754
  $aOldWhere = array(
755
  'pending' => 1,
756
  'deleted_at' => 0,
757
+ 'wp_username' => $sUsername
758
  );
759
  $this->updateRowsFromTable( $aOldData, $aOldWhere );
760
 
761
  // Now add new pending entry
762
+ $aNewData = array();
763
+ $aNewData[ 'unique_id' ] = uniqid();
764
+ $aNewData[ 'ip_long' ] = $this->m_nRequestIp;
765
+ $aNewData[ 'ip' ] = long2ip( $this->m_nRequestIp );
766
+ $aNewData[ 'wp_username' ] = $sUsername;
767
+ $aNewData[ 'pending' ] = 1;
768
+ $aNewData[ 'created_at' ] = time();
769
 
770
+ $mResult = $this->insertIntoTable( $aNewData );
771
  if ( $mResult ) {
772
  $this->logInfo(
773
+ sprintf( _wpsf__('User "%s" created a pending Two-Factor Authentication for IP Address "%s".'), $sUsername, $aNewData[ 'ip' ] )
774
  );
775
+ $mResult = $aNewData;
776
  }
777
  return $mResult;
778
  }
783
  * @param array $inaWhere - unique_id, wp_username
784
  * @return boolean
785
  */
786
+ public function doMakePendingLoginAuthActive( $inaWhere ) {
787
 
788
  $aChecks = array( 'unique_id', 'wp_username' );
789
  if ( !$this->validateParameters( $inaWhere, $aChecks ) ) {
790
  return false;
791
  }
792
 
793
+ // First set any active, non-pending entries for the given user to be deleted
794
+ $this->terminateActiveLoginForUser( $inaWhere['wp_username'] );
795
+
796
+ // Now activate the new one.
797
+
798
+ // Updates the database
799
+ $inaWhere['pending'] = 1;
800
+ $inaWhere['deleted_at'] = 0;
801
+ $mResult = $this->updateRowsFromTable( array( 'pending' => 0 ), $inaWhere );
802
+
803
+ // Set the necessary cookie
804
+ $this->setAuthActiveCookie( $inaWhere['unique_id'] );
805
+ return $mResult;
806
+ }
807
+
808
+ /**
809
+ * Invalidates all currently active two-factor logins and redirects to admin (->login)
810
+ */
811
+ public function doTerminateAllVerifiedLogins() {
812
+ $this->terminateAllVerifiedLogins();
813
+ $oWp = $this->loadWpFunctionsProcessor();
814
+ $oWp->redirectToAdmin();
815
+ }
816
+
817
+ /**
818
+ * @param $sUsername
819
+ */
820
+ protected function setUserLoggedIn( $sUsername ) {
821
+ $oWp = $this->loadWpFunctionsProcessor();
822
+ $oUser = version_compare( $oWp->getWordpressVersion(), '3.2.2', '<=' )? get_userdatabylogin( $sUsername ) : get_user_by( 'login', $sUsername );
823
+
824
+ wp_clear_auth_cookie();
825
+ wp_set_current_user ( $oUser->ID, $oUser->user_login );
826
+ wp_set_auth_cookie ( $oUser->ID, true );
827
+ do_action( 'wp_login', $oUser->user_login );
828
+ }
829
+
830
+ /**
831
+ * Given a username will soft-delete any currently active two-factor authentication.
832
+ *
833
+ * @param $sUsername
834
+ */
835
+ protected function terminateActiveLoginForUser( $sUsername ) {
836
  $sNow = time();
 
 
837
  $sQuery = "
838
  UPDATE `%s`
839
  SET `deleted_at` = '%s',
847
  $this->m_sTableName,
848
  $sNow,
849
  $sNow,
850
+ esc_sql( $sUsername )
851
+ );
852
+ $this->doSql( $sQuery );
853
+ }
854
+
855
+ /**
856
+ *
857
+ */
858
+ protected function terminateAllVerifiedLogins() {
859
+ $sNow = time();
860
+ $sQuery = "
861
+ UPDATE `%s`
862
+ SET `deleted_at` = '%s',
863
+ `expired_at` = '%s'
864
+ WHERE
865
+ `deleted_at` = '0'
866
+ AND `pending` = '0'
867
+ ";
868
+ $sQuery = sprintf( $sQuery,
869
+ $this->m_sTableName,
870
+ $sNow,
871
+ $sNow
872
  );
873
  $this->doSql( $sQuery );
874
+ }
875
+
876
+ /**
877
+ * @param $insUniqueId
878
+ */
879
+ public function setAuthActiveCookie( $insUniqueId ) {
880
+ $nWeek = defined( 'WEEK_IN_SECONDS' )? WEEK_IN_SECONDS : 24*60*60;
881
+ setcookie( self::AuthActiveCookie, $insUniqueId, time()+$nWeek, COOKIEPATH, COOKIE_DOMAIN, false );
 
 
 
 
882
  }
883
 
884
  /**
885
  * Checks whether a given user is authenticated.
886
  *
887
+ * @param string $sUsername
888
  * @return boolean
889
  */
890
+ public function isUserVerified( $sUsername ) {
891
+
 
 
 
 
 
892
  $sQuery = "
893
  SELECT *
894
  FROM `%s`
895
  WHERE
896
  `wp_username` = '%s'
 
897
  AND `pending` = '0'
898
  AND `deleted_at` = '0'
899
  AND `expired_at` = '0'
900
  ";
901
+
902
  $sQuery = sprintf( $sQuery,
903
  $this->m_sTableName,
904
+ $sUsername
 
905
  );
906
 
907
  $mResult = $this->selectCustomFromTable( $sQuery );
908
+
909
  if ( is_array( $mResult ) && count( $mResult ) == 1 ) {
910
+ // Now we test based on which types of 2-factor auth is enabled
911
+ $fVerified = true;
912
+ $aUserAuthData = $mResult[0];
913
+ if ( $this->getIsTwoFactorAuthOn('ip') && ( $this->m_nRequestIp != $aUserAuthData['ip_long'] ) ) {
914
+ $fVerified = false;
915
+ }
916
+ if ( $fVerified && $this->getIsTwoFactorAuthOn('cookie') && !$this->isAuthCookieValid($aUserAuthData['unique_id']) ) {
917
+ $fVerified = false;
918
+ }
919
+ return $fVerified;
920
  }
921
  else {
922
  $this->logWarning(
923
+ sprintf( _wpsf__('User "%s" was found to be un-verified at the given IP Address "%s"'), $sUsername, long2ip( $this->m_nRequestIp ) )
924
  );
925
  return false;
926
  }
927
  }
928
+
929
+ /**
930
+ * @param $sUniqueId
931
+ * @return bool
932
+ */
933
+ protected function isAuthCookieValid( $sUniqueId ) {
934
+ $this->loadDataProcessor();
935
+ return ICWP_WPSF_DataProcessor::FetchCookie( self::AuthActiveCookie ) == $sUniqueId;
936
+ }
937
+
938
+ /**
939
+ * If it cannot verify current user, will forcefully log them out and redirect to login
940
+ */
941
  public function verifyCurrentUser() {
942
  $oUser = wp_get_current_user();
943
  if ( is_object( $oUser ) && $oUser instanceof WP_User ) {
944
 
945
+ if ( $this->getIsUserLevelSubjectToTwoFactorAuth( $oUser->user_level ) && !$this->isUserVerified( $oUser->user_login ) ) {
 
946
  $this->logWarning(
947
+ sprintf( _wpsf__('User "%s" was forcefully logged out as they are not verified.'), $oUser->user_login )
948
  );
949
+ $this->doStatIncrement( 'login.userverify.fail' );
950
  wp_logout();
951
+ $oWp = $this->loadWpFunctionsProcessor();
952
+ $oWp->redirectToLogin();
953
  }
954
  }
955
  }
957
  /**
958
  * Given the necessary components, creates the 2-factor verification link for giving to the user.
959
  *
960
+ * @param string $sUser
961
+ * @param string $sUniqueId
 
962
  * @return string
963
  */
964
+ protected function generateTwoFactorVerifyLink( $sUser, $sUniqueId ) {
965
  $sSiteUrl = home_url() . '?wpsfkey=%s&wpsf-action=%s&username=%s&uniqueid=%s';
966
  $sAction = 'linkauth';
967
+ return sprintf( $sSiteUrl, $this->m_sSecretKey, $sAction, $sUser, $sUniqueId );
968
  }
969
 
970
  /**
971
+ * @param WP_User $inoUser
972
  * @param string $insIpAddress
973
+ * @param string $insUniqueId
974
+ * @return boolean
975
  */
976
  public function sendEmailTwoFactorVerify( WP_User $inoUser, $insIpAddress, $insUniqueId ) {
977
 
978
  $sEmail = $inoUser->user_email;
979
+ $sAuthLink = $this->generateTwoFactorVerifyLink( $inoUser->user_login, $insUniqueId );
980
 
981
  $aMessage = array(
982
+ _wpsf__('You, or someone pretending to be you, just attempted to login into your WordPress site.'),
983
+ _wpsf__('The IP Address / Cookie from which they tried to login is not currently verified.'),
984
+ _wpsf__('To validate this user, click the following link and then attempt to login again.'),
985
+ sprintf( _wpsf__('IP Address: %s'), $insIpAddress ),
986
+ sprintf( _wpsf__('Authentication Link: %s'), $sAuthLink ),
987
  );
988
+ $sEmailSubject = sprintf( _wpsf__('Two-Factor Login Verification for: %s'), home_url() );
989
+
990
+ // add filters to email sending (for now only Mandrill)
991
+ add_filter( 'mandrill_payload', array($this, 'customiseMandrill') );
992
+
993
  $fResult = $this->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
994
  if ( $fResult ) {
995
  $this->logInfo(
996
+ 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 )
997
  );
998
  }
999
  else {
1000
  $this->logCritical(
1001
+ 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 )
1002
  );
1003
  }
1004
  return $fResult;
1005
  }
1006
+
1007
+ /**
1008
+ *
1009
+ */
1010
+ public function customiseMandrill( $aMessage ) {
1011
+ if ( empty( $aMessage['text'] ) ) {
1012
+ $aMessage['text'] = $aMessage['html'];
1013
+ }
1014
+ return $aMessage;
1015
+ }
1016
 
1017
  public function createTable() {
1018
 
1045
  $sQuery = sprintf( $sQuery, $this->m_sTableName, $inaData['unique_id'], $inaData['wp_username'] );
1046
  return $this->selectRowFromTable( $sQuery );
1047
  }
1048
+
1049
+ /**
1050
+ * This is hooked into a cron in the base class and overrides the parent method.
1051
+ *
1052
+ * It'll delete everything older than 24hrs.
1053
+ */
1054
+ public function cleanupDatabase() {
1055
+ if ( !$this->getTableExists() ) {
1056
+ return;
1057
+ }
1058
+ $nTimeStamp = time() - (DAY_IN_SECONDS * $this->nDaysToKeepLog);
1059
+ $this->deleteAllRowsOlderThan( $nTimeStamp );
1060
+ }
1061
+
1062
+ /**
1063
+ * @param $nTimeStamp
1064
+ */
1065
+ protected function deleteAllRowsOlderThan( $nTimeStamp ) {
1066
+ $sQuery = "
1067
+ DELETE from `%s`
1068
+ WHERE
1069
+ `created_at` < '%s'
1070
+ AND `pending` = '1'
1071
+ ";
1072
+ $sQuery = sprintf( $sQuery,
1073
+ $this->m_sTableName,
1074
+ esc_sql( $nTimeStamp )
1075
+ );
1076
+ $this->doSql( $sQuery );
1077
+ }
1078
+
1079
  }
1080
+ endif;
1081
 
1082
+ if ( !class_exists('ICWP_WPSF_LoginProtectProcessor') ):
1083
+ class ICWP_WPSF_LoginProtectProcessor extends ICWP_LoginProtectProcessor_V2 { }
1084
  endif;
src/icwp-processor-privacyprotect.php ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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_PrivacyProtectProcessor_V1') ):
21
+
22
+ class ICWP_PrivacyProtectProcessor_V1 extends ICWP_BaseDbProcessor_WPSF {
23
+
24
+ const Slug = 'privacy_protect';
25
+
26
+ public function __construct( $insOptionPrefix = '' ) {
27
+ parent::__construct( $this->constructStorageKey( $insOptionPrefix, self::Slug ), self::Slug );
28
+ $this->createTable();
29
+ $this->reset();
30
+ }
31
+
32
+ /**
33
+ * Resets the object values to be re-used anew
34
+ */
35
+ public function reset() {
36
+ parent::reset();
37
+ $this->m_sUniqueToken = '';
38
+ $this->m_sCommentStatus = '';
39
+ }
40
+
41
+ /**
42
+ */
43
+ public function run() {
44
+ parent::run();
45
+ if ( $this->getOption('enable_privacy_protect') == 'Y' ) {
46
+ add_action( 'http_api_debug', array( $this, 'logHttpRequest' ), 1000, 5 );
47
+ add_filter( 'http_request_args', array( $this, 'cleanHttpRequestData' ), 1000, 2 );
48
+ }
49
+ }
50
+
51
+ /**
52
+ * @param $oHttpResponse
53
+ * @param $sResponse
54
+ * @param $sCallingClass
55
+ * @param $aRequestArgs
56
+ * @param $sRequestUrl
57
+ * @return bool
58
+ */
59
+ public function logHttpRequest( $oHttpResponse, $sResponse, $sCallingClass, $aRequestArgs, $sRequestUrl ) {
60
+
61
+ if ( $this->getOption('ignore_local_requests') == 'Y' && $this->getIsLocalRequest($aRequestArgs) ) {
62
+ return true;
63
+ }
64
+
65
+ // Now add new pending entry
66
+ $nNow = time();
67
+ $aData = array();
68
+ $aData[ 'request_url' ] = $sRequestUrl;
69
+ $aData[ 'request_method' ] = $aRequestArgs['method'];
70
+ $aData[ 'is_ssl' ] = strpos( $sRequestUrl, 'https' ) === 0? 1 : 0;
71
+ $aData[ 'is_error' ] = is_wp_error( $oHttpResponse )? 1 : 0;
72
+ $aData[ 'request_args' ] = serialize( $aRequestArgs );
73
+ $aData[ 'requested_at' ] = $nNow;
74
+
75
+ $mResult = $this->insertIntoTable( $aData );
76
+ return $mResult;
77
+ }
78
+
79
+ /**
80
+ * @param $aRequestArgs
81
+ * @param $sRequestUrl
82
+ * @return mixed
83
+ */
84
+ public function cleanHttpRequestData( $aRequestArgs, $sRequestUrl ) {
85
+
86
+ $sSiteUrl = str_replace( array( 'http://', 'https://' ), '', network_home_url() );
87
+ $sRandomUrl = $this->generateRandomString().'.com';
88
+
89
+ if ( $this->getOption('filter_site_url') == 'Y'
90
+ || ( $this->getOption('filter_wordpressorg_update_data') == 'Y' && ( strpos( $sRequestUrl, 'wordpress.org' ) !== false ) )
91
+ ) {
92
+ $aRequestArgs['user-agent'] = str_replace( $sSiteUrl, $sRandomUrl, $aRequestArgs['user-agent'] );
93
+
94
+ $aHeaders = $aRequestArgs['headers'];
95
+ foreach( $aHeaders as $sKey => $sValue ) {
96
+ $aHeaders[$sKey] = str_replace( $sSiteUrl, $sRandomUrl, $aHeaders[$sKey] );
97
+ }
98
+ $aRequestArgs['headers'] = $aHeaders;
99
+
100
+ $aRequestArgs['icwp_wpsf'] = _wpsf__( 'Site URL filtered by the WordPress Simple Firewall plugin' );
101
+
102
+ // Now filter the URL only if it isn't LOCAL
103
+ if ( isset( $aRequestArgs['local'] ) && $aRequestArgs['local'] != 1 ) {
104
+ //unfortunately can't filter the URL.
105
+ //TODO: $pre = apply_filters( 'pre_http_request', false, $r, $url );
106
+ }
107
+
108
+ // if ( isset($aRequestArgs['headers']['wp_install']) ) {
109
+ // $aRequestArgs['headers']['wp_install'] = str_replace( $sSiteUrl, $sRandomUrl, $aRequestArgs['headers']['wp_install'] );
110
+ // }
111
+ // if ( isset($aRequestArgs['headers']['wp_blog']) ) {
112
+ // $aRequestArgs['headers']['wp_blog'] = str_replace( $sSiteUrl, $sRandomUrl, $aRequestArgs['headers']['wp_blog'] );
113
+ // }
114
+ }
115
+ return $aRequestArgs;
116
+ }
117
+
118
+ /**
119
+ * @param $aRequestArgs
120
+ * @return bool
121
+ */
122
+ protected function getIsLocalRequest( &$aRequestArgs ) {
123
+ return isset( $aRequestArgs['local'] ) && $aRequestArgs['local'] == 1;
124
+ }
125
+
126
+ /**
127
+ * @param int $nLength
128
+ * @return string
129
+ */
130
+ protected function generateRandomString( $nLength = 10 ) {
131
+ $sCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
132
+ $sRandomString = '';
133
+ for ($i = 0; $i < $nLength; $i++) {
134
+ $sRandomString .= $sCharacters[rand(0, strlen($sCharacters) - 1)];
135
+ }
136
+ return $sRandomString;
137
+ }
138
+
139
+ /**
140
+ * @param boolean $infReverseOrder
141
+ * @return array - numerical array of all log data entries.
142
+ */
143
+ public function getLogs( $infReverseOrder = false ) {
144
+ $aLogData = $this->selectAllFromTable();
145
+ if ( $infReverseOrder && $aLogData && is_array( $aLogData ) ) {
146
+ $aLogData = array_reverse( $aLogData );
147
+ }
148
+ return $aLogData;
149
+ }
150
+
151
+ public function createTable() {
152
+ $sSqlTables = "CREATE TABLE IF NOT EXISTS `%s` (
153
+ `id` int(11) NOT NULL AUTO_INCREMENT,
154
+ `request_url` varchar(255) NOT NULL DEFAULT '',
155
+ `request_port` mediumint(5) UNSIGNED NOT NULL DEFAULT 80,
156
+ `request_method` varchar(4) NOT NULL DEFAULT 'GET',
157
+ `request_args` text NOT NULL DEFAULT '',
158
+ `is_ssl` tinyint(1) NOT NULL DEFAULT 0,
159
+ `is_error` tinyint(1) NOT NULL DEFAULT 0,
160
+ `requested_at` int(15) NOT NULL DEFAULT 0,
161
+ `deleted_at` int(15) NOT NULL DEFAULT 0,
162
+ PRIMARY KEY (`id`)
163
+ ) ENGINE=MyISAM DEFAULT CHARSET=utf8;";
164
+ $sSqlTables = sprintf( $sSqlTables, $this->m_sTableName );
165
+ $mResult = $this->doSql( $sSqlTables );
166
+ }
167
+ }
168
+
169
+ endif;
170
+
171
+ if ( !class_exists('ICWP_WPSF_PrivacyProtectProcessor') ):
172
+ class ICWP_WPSF_PrivacyProtectProcessor extends ICWP_PrivacyProtectProcessor_V1 { }
173
+ endif;
src/icwp-pure-base.php ADDED
@@ -0,0 +1,966 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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_V4') ):
12
+
13
+ class ICWP_Pure_Base_V4 extends ICWP_WPSF_Once {
14
+
15
+ const BaseTitle = 'iControlWP Plugins';
16
+ const BaseSlug = 'icwp';
17
+ const BasePermissions = 'manage_options';
18
+
19
+ const ViewExt = '.php';
20
+ const ViewDir = 'views';
21
+
22
+ /**
23
+ * @var string
24
+ */
25
+ protected $m_sVersion;
26
+ /**
27
+ * Set to true if it should never be shown in the dashboard
28
+ * @var string
29
+ */
30
+ protected $m_fHeadless = false;
31
+ /**
32
+ * Set to true if this contains components from another plugin to stand alone
33
+ * @var string
34
+ */
35
+ protected $m_fStandAlone = false;
36
+ /**
37
+ * Set to true if this contains components from another plugin to stand alone
38
+ * @var string
39
+ */
40
+ protected $m_sAutoUpdateUrl = '';
41
+ /**
42
+ * @var boolean
43
+ */
44
+ protected $m_fIsMultisite;
45
+ /**
46
+ * @var boolean
47
+ */
48
+ protected $m_fNetworkAdminOnly = false;
49
+
50
+ /**
51
+ * @var string
52
+ */
53
+ protected $m_sPluginHumanName;
54
+ /**
55
+ * @var string
56
+ */
57
+ protected $m_sPluginTextDomain;
58
+ /**
59
+ * @var string
60
+ */
61
+ protected $m_sPluginMenuTitle;
62
+
63
+ /**
64
+ * @var string
65
+ */
66
+ protected $m_sPluginRootFile;
67
+ /**
68
+ * @var string
69
+ */
70
+ protected $m_sPluginName;
71
+ /**
72
+ * @var string
73
+ */
74
+ protected $m_sPluginDir;
75
+ /**
76
+ * @var string
77
+ */
78
+ protected $m_sPluginPath;
79
+ /**
80
+ * @var string
81
+ */
82
+ protected $m_sPluginFile;
83
+ /**
84
+ * @var string
85
+ */
86
+ protected $m_sPluginUrl;
87
+ /**
88
+ * @var string
89
+ */
90
+ protected static $sOptionPrefix = '';
91
+
92
+ protected $m_aPluginMenu;
93
+
94
+ protected $m_sParentMenuIdSuffix;
95
+
96
+ protected $m_sPluginSlug;
97
+
98
+ protected $fShowMarketing;
99
+
100
+ protected $m_fAutoPluginUpgrade = false;
101
+
102
+ /**
103
+ * @var ICWP_WpFunctions_WPSF;
104
+ */
105
+ protected $m_oWpFunctions;
106
+
107
+ /**
108
+ * @var ICWP_WpFilesystem_WPSF;
109
+ */
110
+ protected $m_oWpFs;
111
+
112
+ public function __construct() {
113
+
114
+ add_action( 'plugins_loaded', array( $this, 'onWpPluginsLoaded' ) );
115
+ add_action( 'init', array( $this, 'onWpInit' ), 0 );
116
+ if ( $this->isValidAdminArea() ) {
117
+ add_action( 'admin_init', array( $this, 'onWpAdminInit' ) );
118
+ add_action( 'admin_notices', array( $this, 'onWpAdminNotices' ) );
119
+ add_action( 'network_admin_notices', array( $this, 'onWpAdminNotices' ) );
120
+ add_action( 'admin_menu', array( $this, 'onWpAdminMenu' ) );
121
+ add_action( 'network_admin_menu', array( $this, 'onWpNetworkAdminMenu' ) );
122
+ add_action( 'plugin_action_links', array( $this, 'onWpPluginActionLinks' ), 10, 4 );
123
+ add_action( 'deactivate_plugin', array( $this, 'onWpHookDeactivatePlugin' ), 1, 1 );
124
+ add_action( 'wp_before_admin_bar_render', array( $this, 'onWpAdminBar' ), 1, 9999 );
125
+ }
126
+ add_action( 'in_plugin_update_message-'.$this->m_sPluginFile, array( $this, 'onWpPluginUpdateMessage' ) );
127
+ add_action( 'shutdown', array( $this, 'onWpShutdown' ) );
128
+
129
+ $this->m_fIsMultisite = function_exists( 'is_multisite' ) && is_multisite();
130
+ $this->m_oWpFs = ICWP_WpFilesystem_WPSF::GetInstance();
131
+ $this->setPaths();
132
+ $this->registerActivationHooks();
133
+ }
134
+
135
+ /**
136
+ * This is a generic plugin auto-update checker. Since the library is never included WordPress.org
137
+ * plugins, this may never actually run.
138
+ *
139
+ * @return void
140
+ */
141
+ protected function setupAutoUpdates() {
142
+ $sLibSource = $this->m_sPluginDir.'/src/lib/plugin-update-checker.php';
143
+ if ( !is_file($sLibSource) || empty( $this->m_sAutoUpdateUrl ) ) {
144
+ return;
145
+ }
146
+ require_once( $sLibSource );
147
+ $oUpdateChecker = new PluginUpdateChecker(
148
+ $this->m_sAutoUpdateUrl,
149
+ $this->m_sPluginRootFile,
150
+ $this->m_sPluginTextDomain
151
+ );
152
+ }
153
+
154
+ protected function isValidAdminArea() {
155
+ if ( !$this->m_fIsMultisite && is_admin() ) {
156
+ return true;
157
+ }
158
+ else if ( $this->m_fNetworkAdminOnly && $this->m_fIsMultisite && is_network_admin() ) {
159
+ return true;
160
+ }
161
+ return false;
162
+ }
163
+
164
+ /**
165
+ * Registers the plugins activation, deactivate and uninstall hooks.
166
+ */
167
+ protected function registerActivationHooks() {
168
+ register_activation_hook( $this->m_sPluginRootFile, array( $this, 'onWpActivatePlugin' ) );
169
+ register_deactivation_hook( $this->m_sPluginRootFile, array( $this, 'onWpDeactivatePlugin' ) );
170
+ // register_uninstall_hook( $this->m_sPluginRootFile, array( $this, 'onWpUninstallPlugin' ) );
171
+ }
172
+
173
+ /**
174
+ * @since v3.0.0
175
+ */
176
+ protected function setPaths() {
177
+
178
+ if ( empty( $this->m_sPluginRootFile ) ) {
179
+ $this->m_sPluginRootFile = __FILE__;
180
+ }
181
+ $this->m_sPluginName = basename( $this->m_sPluginRootFile );
182
+ $this->m_sPluginPath = plugin_basename( dirname( $this->m_sPluginRootFile ) );
183
+ $this->m_sPluginFile = plugin_basename( $this->m_sPluginRootFile );
184
+ $this->m_sPluginDir = dirname( $this->m_sPluginRootFile ).ICWP_DS;
185
+ $this->m_sPluginUrl = plugins_url( '/', $this->m_sPluginRootFile ) ; //this seems to use SSL more reliably than WP_PLUGIN_URL
186
+ }
187
+
188
+ /**
189
+ * @return string
190
+ */
191
+ public function getPluginFile() {
192
+ return $this->m_sPluginFile;
193
+ }
194
+
195
+ /**
196
+ * @return boolean
197
+ */
198
+ protected function hasPermissionToView() {
199
+ return $this->hasPermissionToSubmit();
200
+ }
201
+ /**
202
+ * @return boolean
203
+ */
204
+ protected function hasPermissionToSubmit() {
205
+ // first a basic admin check
206
+ return is_super_admin() && current_user_can( 'manage_options' );
207
+ }
208
+
209
+ public function doPluginUpdateCheck() {
210
+ $this->loadWpFunctions();
211
+ $this->m_oWpFunctions->getIsPluginUpdateAvailable( $this->m_sPluginPath );
212
+ }
213
+
214
+ protected function getFullParentMenuId() {
215
+ return self::BaseSlug .'-'. $this->m_sParentMenuIdSuffix;
216
+ }
217
+
218
+ protected function display( $insView, $inaData = array() ) {
219
+ $sFile = $this->m_sPluginDir.self::ViewDir.ICWP_DS.$insView.self::ViewExt;
220
+
221
+ if ( !is_file( $sFile ) ) {
222
+ echo "View not found: ".$sFile;
223
+ return false;
224
+ }
225
+
226
+ if ( count( $inaData ) > 0 ) {
227
+ extract( $inaData, EXTR_PREFIX_ALL, self::BaseSlug );
228
+ }
229
+
230
+ ob_start();
231
+ include( $sFile );
232
+ $sContents = ob_get_contents();
233
+ ob_end_clean();
234
+
235
+ echo $sContents;
236
+ return true;
237
+ }
238
+
239
+ protected function getSubmenuPageTitle( $insTitle ) {
240
+ return self::BaseTitle.' - '.$insTitle;
241
+ }
242
+ protected function getSubmenuId( $insId = '' ) {
243
+ $sExtension = empty($insId)? '' : '-'.$insId;
244
+ return $this->getFullParentMenuId().$sExtension;
245
+ }
246
+
247
+ /**
248
+ * Hooked to 'plugins_loaded'
249
+ */
250
+ public function onWpPluginsLoaded() {
251
+ $this->setupAutoUpdates();
252
+ if ( is_admin() ) {
253
+ //Handle plugin upgrades
254
+ $this->handlePluginUpgrade();
255
+ $this->doPluginUpdateCheck();
256
+ $this->load_textdomain();
257
+ }
258
+ if ( $this->isIcwpPluginFormSubmit() ) {
259
+ $this->handlePluginFormSubmit();
260
+ }
261
+ add_filter( 'all_plugins', array( $this, 'hidePluginFromTableList' ) );
262
+ add_filter( 'site_transient_update_plugins', array( $this, 'hidePluginUpdatesFromUI' ) );
263
+ $this->removePluginConflicts(); // removes conflicts with other plugins
264
+ }
265
+
266
+ /**
267
+ * Override this to remove conflicts with other plugins that may have loaded
268
+ * that interfere with normal operations.
269
+ */
270
+ protected function removePluginConflicts() {}
271
+
272
+ /**
273
+ * Added to a WordPress filter ('all_plugins') which will remove this particular plugin from the
274
+ * list of all plugins based on the "plugin file" name.
275
+ *
276
+ * @uses $this->m_fHeadless if the plugin is headless, it is hidden
277
+ * @return array
278
+ */
279
+ public function hidePluginFromTableList( $inaPlugins ) {
280
+
281
+ if ( !$this->m_fHeadless ) {
282
+ return $inaPlugins;
283
+ }
284
+
285
+ foreach ( $inaPlugins as $sName => $aData ) {
286
+ if ( $this->m_sPluginFile === $sName ) {
287
+ unset( $inaPlugins[$sName] );
288
+ }
289
+ }
290
+ return $inaPlugins;
291
+ }
292
+
293
+ /**
294
+ * Added to the WordPress filter ('site_transient_update_plugins') in order to remove visibility of updates
295
+ * from the WordPress Admin UI.
296
+ *
297
+ * In order to ensure that WordPress still checks for plugin updates it will not remove this plugin from
298
+ * the list of plugins if DOING_CRON is set to true.
299
+ *
300
+ * @uses $this->m_fHeadless if the plugin is headless, it is hidden
301
+ * @return StdClass
302
+ */
303
+ public function hidePluginUpdatesFromUI( $inoPlugins ) {
304
+
305
+ if ( ( defined( 'DOING_CRON' ) && DOING_CRON ) || !$this->m_fHeadless ) {
306
+ return $inoPlugins;
307
+ }
308
+
309
+ if ( !empty( $inoPlugins->response ) ) {
310
+ $aResponse = $inoPlugins->response;
311
+ foreach ( $aResponse as $sPluginFile => $oData ) {
312
+ if ( $sPluginFile == $this->m_sPluginFile ) {
313
+ unset( $inoPlugins->response[$sPluginFile] );
314
+ }
315
+ }
316
+ }
317
+ return $inoPlugins;
318
+ }
319
+
320
+ /**
321
+ * Load the multilingual aspect of the plugin
322
+ */
323
+ public function load_textdomain() {
324
+ $stest = dirname( $this->m_sPluginRootFile );
325
+ // var_dump($stest);
326
+ // var_dump($this->m_sPluginTextDomain);
327
+ load_plugin_textdomain( $this->m_sPluginTextDomain, false, dirname($this->m_sPluginFile) . '/languages/' );
328
+ }
329
+
330
+ public function onWpInit() { }
331
+
332
+ public function onWpAdminInit() {
333
+ //Do Plugin-Specific Admin Work
334
+ if ( $this->isIcwpPluginAdminPage() ) {
335
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueueBootstrapLegacyAdminCss' ), 99 );
336
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueuePluginAdminCss' ), 99 );
337
+ }
338
+ }
339
+
340
+ public function onWpAdminMenu() {
341
+ if ( !$this->isValidAdminArea() ) {
342
+ return true;
343
+ }
344
+ $this->createMenu();
345
+ }
346
+
347
+ public function onWpNetworkAdminMenu() {
348
+ if ( !$this->isValidAdminArea() ) {
349
+ return true;
350
+ }
351
+ $this->createMenu();
352
+ }
353
+
354
+ protected function createMenu() {
355
+
356
+ if ( $this->m_fHeadless ) {
357
+ return true;
358
+ }
359
+
360
+ $sFullParentMenuId = $this->getFullParentMenuId();
361
+ add_menu_page( self::BaseTitle, $this->m_sPluginMenuTitle, self::BasePermissions, $sFullParentMenuId, array( $this, 'onDisplayAll' ), $this->getPluginLogoUrl16() );
362
+ //Create and Add the submenu items
363
+ $this->createPluginSubMenuItems();
364
+ if ( !empty($this->m_aPluginMenu) ) {
365
+ foreach ( $this->m_aPluginMenu as $sMenuTitle => $aMenu ) {
366
+ list( $sMenuItemText, $sMenuItemId, $sMenuCallBack ) = $aMenu;
367
+ add_submenu_page( $sFullParentMenuId, $sMenuTitle, $sMenuItemText, self::BasePermissions, $sMenuItemId, array( $this, $sMenuCallBack ) );
368
+ }
369
+ }
370
+ $this->fixSubmenu();
371
+ }
372
+
373
+ protected function createPluginSubMenuItems(){
374
+ /* Override to create array of sub-menu items
375
+ $this->m_aPluginMenu = array(
376
+ //Menu Page Title => Menu Item name, page ID (slug), callback function onLoad.
377
+ $this->getSubmenuPageTitle( 'Content by Country' ) => array( 'Content by Country', $this->getSubmenuId('main'), 'onDisplayCbcMain' ),
378
+ );
379
+ */
380
+ }
381
+
382
+ protected function fixSubmenu() {
383
+ global $submenu;
384
+ $sFullParentMenuId = $this->getFullParentMenuId();
385
+ if ( isset( $submenu[$sFullParentMenuId] ) ) {
386
+ $submenu[$sFullParentMenuId][0][0] = 'Dashboard';
387
+ }
388
+ }
389
+
390
+ /**
391
+ * Displaying all views now goes through this central function and we work out
392
+ * what to display based on the name of current hook/filter being processed.
393
+ */
394
+ public function onDisplayAll() {
395
+ $this->onDisplayMainMenu();
396
+ }
397
+
398
+ /**
399
+ * The callback function for the main admin menu index page
400
+ */
401
+ public function onDisplayMainMenu() {
402
+ $aData = array(
403
+ 'plugin_url' => $this->m_sPluginUrl,
404
+ 'fShowAds' => $this->isShowMarketing()
405
+ );
406
+ $this->display( self::BaseSlug.'_'.$this->m_sParentMenuIdSuffix.'_index', $aData );
407
+ }
408
+
409
+ protected function getBaseDisplayData( $insSubmenuId = '' ) {
410
+ return array(
411
+ 'plugin_url' => $this->m_sPluginUrl,
412
+ 'var_prefix' => self::$sOptionPrefix,
413
+ 'sPluginName' => $this->m_sPluginHumanName,
414
+ 'fShowAds' => $this->isShowMarketing(),
415
+ 'nonce_field' => $this->getSubmenuId( $insSubmenuId ),
416
+ 'form_action' => 'admin.php?page='.$this->getSubmenuId( $insSubmenuId )
417
+ );
418
+ }
419
+
420
+ /**
421
+ * @return bool
422
+ */
423
+ protected function isShowMarketing() {
424
+
425
+ if ( isset($this->fShowMarketing) ) {
426
+ return $this->fShowMarketing;
427
+ }
428
+ $this->fShowMarketing = true;
429
+ if ( class_exists( 'Worpit_Plugin' ) ) {
430
+ if ( method_exists( 'Worpit_Plugin', 'IsLinked' ) ) {
431
+ $this->fShowMarketing = !Worpit_Plugin::IsLinked();
432
+ }
433
+ else if ( function_exists( 'get_option' )
434
+ && get_option( Worpit_Plugin::$VariablePrefix.'assigned' ) == 'Y'
435
+ && get_option( Worpit_Plugin::$VariablePrefix.'assigned_to' ) != '' ) {
436
+
437
+ $this->fShowMarketing = false;
438
+ }
439
+ }
440
+ return $this->fShowMarketing ;
441
+ }
442
+
443
+ /**
444
+ * On the plugins listing page, hides the edit and deactivate links
445
+ * for this plugin based on permissions
446
+ *
447
+ * @see ICWP_Pure_Base_V1::onWpPluginActionLinks()
448
+ */
449
+ public function onWpPluginActionLinks( $inaActionLinks, $insFile ) {
450
+
451
+ if ( $insFile == $this->m_sPluginFile ) {
452
+ if ( !$this->hasPermissionToSubmit() ) {
453
+ if ( array_key_exists( 'edit', $inaActionLinks ) ) {
454
+ unset( $inaActionLinks['edit'] );
455
+ }
456
+ if ( array_key_exists( 'deactivate', $inaActionLinks ) ) {
457
+ unset( $inaActionLinks['deactivate'] );
458
+ }
459
+ }
460
+ $sSettingsLink = '<a href="'.network_admin_url( "admin.php" ).'?page='.$this->getSubmenuId().'">' . 'Dashboard' . '</a>';
461
+ array_unshift( $inaActionLinks, $sSettingsLink );
462
+ }
463
+ return $inaActionLinks;
464
+ }
465
+
466
+ /**
467
+ * Override this method to handle all the admin notices
468
+ */
469
+ public function onWpAdminNotices() {
470
+ // Do we have admin priviledges?
471
+ if ( !$this->isValidAdminArea() || !current_user_can( 'manage_options' ) ) {
472
+ return true;
473
+ }
474
+
475
+ $this->doAdminNoticeOptionsUpdated();
476
+
477
+ // If we've set to not show admin notices ever
478
+ if ( $this->getShowAdminNotices() ) {
479
+
480
+ if ( $this->hasPermissionToView() ) {
481
+ $this->doAdminNoticePostUpgrade();
482
+ $this->doAdminNoticeTranslations();
483
+ $this->doAdminNoticeMailingListSignup();
484
+ }
485
+ if ( $this->hasPermissionToSubmit() ) {
486
+ $this->doAdminNoticePluginUpgradeAvailable();
487
+ }
488
+ }
489
+ }
490
+
491
+ protected function doAdminNoticePluginUpgradeAvailable() {
492
+
493
+ // Don't show on the update page.
494
+ if ( isset( $GLOBALS['pagenow'] ) && $GLOBALS['pagenow'] == 'update.php' ) {
495
+ return;
496
+ }
497
+ // We need to have the correct plugin file set before proceeding.
498
+ if ( !isset( $this->m_sPluginFile ) ) {
499
+ return;
500
+ }
501
+
502
+ $this->loadWpFunctions();
503
+ $oUpdate = $this->m_oWpFunctions->getIsPluginUpdateAvailable( $this->m_sPluginFile );
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->m_sVersion ) {
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->m_sPluginFile );
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->m_sPluginHumanName, $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
+ * Updates the current (or supplied user ID) user meta data with the version of the plugin
620
+ *
621
+ * @param $nId
622
+ * @param $sValue
623
+ */
624
+ protected function updateMailingListSignupShownUserMeta( $nId = '', $sValue = 'Y' ) {
625
+ $this->updateUserMeta( 'plugin_mailing_list_signup', $sValue, $nId );
626
+ }
627
+
628
+ /**
629
+ * Updates the current (or supplied user ID) user meta data with the version of the plugin
630
+ *
631
+ * @param unknown_type $innId
632
+ */
633
+ protected function updateVersionUserMeta( $innId = '' ) {
634
+ $this->updateUserMeta( 'current_version', $this->m_sVersion, $innId );
635
+ }
636
+
637
+ /**
638
+ * Updates the current (or supplied user ID) user meta data with the version of the plugin
639
+ *
640
+ * @param string $insKey
641
+ * @param mixed $mValue
642
+ * @param integer $innId -user ID
643
+ * @return boolean
644
+ */
645
+ protected function updateUserMeta( $insKey, $mValue, $innId = null ) {
646
+ if ( empty( $innId ) ) {
647
+ $oCurrentUser = $this->getCurrentUser();
648
+ if ( !$oCurrentUser ) {
649
+ return;
650
+ }
651
+ $nUserId = $oCurrentUser->ID;
652
+ }
653
+ else {
654
+ $nUserId = $innId;
655
+ }
656
+ return update_user_meta( $nUserId, self::$sOptionPrefix.$insKey, $mValue );
657
+ }
658
+
659
+ protected function getUserMeta( $sKey ) {
660
+
661
+ $oCurrentUser = $this->getCurrentUser();
662
+ if ( !$oCurrentUser ) {
663
+ return;
664
+ }
665
+ $nUserId = $oCurrentUser->ID;
666
+
667
+ $sCurrentMetaValue = get_user_meta( $nUserId, self::$sOptionPrefix.$sKey, true );
668
+ // A guard whereby if we can't ever get a value for this meta, it means we can never set it.
669
+ if ( empty( $sCurrentMetaValue ) ) {
670
+ //the value has never been set, or it's been installed for the first time.
671
+ $this->updateUserMeta( $sKey, 'temp', $nUserId );
672
+ 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.
673
+ }
674
+ return $sCurrentMetaValue;
675
+ }
676
+
677
+ /**
678
+ * @return mixed
679
+ */
680
+ protected function getCurrentUser() {
681
+ if( !is_user_logged_in() ) {
682
+ return false;
683
+ }
684
+ global $current_user;
685
+ get_currentuserinfo();
686
+ return $current_user;
687
+ }
688
+
689
+ /**
690
+ * This is called from within onWpAdminInit. Use this solely to manage upgrades of the plugin
691
+ */
692
+ protected function handlePluginUpgrade() {
693
+ if ( !is_admin() || !current_user_can( 'manage_options' ) ) {
694
+ return;
695
+ }
696
+ if ( $this->m_fAutoPluginUpgrade ) {
697
+ $this->loadWpFunctions();
698
+ $this->m_oWpFunctions->doPluginUpgrade( $this->m_sPluginFile );
699
+ }
700
+ }
701
+
702
+ protected function handlePluginFormSubmit() { }
703
+
704
+ protected function isIcwpPluginFormSubmit() {
705
+ return isset( $_POST['icwp_plugin_form_submit'] );
706
+ }
707
+
708
+ protected function isIcwpPluginAdminPage() {
709
+ $sSubPageNow = isset( $_GET['page'] )? $_GET['page']: '';
710
+ if ( is_admin() && !empty($sSubPageNow) && (strpos( $sSubPageNow, $this->getFullParentMenuId() ) === 0 )) { //admin area, and the 'page' begins with 'worpit'
711
+ return true;
712
+ }
713
+ return false;
714
+ }
715
+
716
+ public function enqueueBootstrapAdminCss() {
717
+ wp_register_style( self::$sOptionPrefix.'bootstrap_wpadmin_css', $this->getCssUrl( 'bootstrap-wpadmin.css' ), false, $this->m_sVersion );
718
+ wp_enqueue_style( self::$sOptionPrefix.'bootstrap_wpadmin_css' );
719
+ }
720
+
721
+ public function enqueueBootstrapLegacyAdminCss() {
722
+ wp_register_style( self::$sOptionPrefix.'bootstrap_wpadmin_legacy_css', $this->getCssUrl( 'bootstrap-wpadmin-legacy.css' ), false, $this->m_sVersion );
723
+ wp_enqueue_style( self::$sOptionPrefix.'bootstrap_wpadmin_legacy_css' );
724
+ wp_register_style( self::$sOptionPrefix.'bootstrap_wpadmin_css_fixes', $this->getCssUrl('bootstrap-wpadmin-fixes.css'), array( self::$sOptionPrefix.'bootstrap_wpadmin_legacy_css'), $this->m_sVersion );
725
+ wp_enqueue_style( self::$sOptionPrefix.'bootstrap_wpadmin_css_fixes' );
726
+ }
727
+
728
+ public function enqueuePluginAdminCss() {
729
+ wp_register_style( self::$sOptionPrefix.'plugin_css', $this->getCssUrl('plugin.css'), array(self::$sOptionPrefix.'bootstrap_wpadmin_css_fixes'), $this->m_sVersion );
730
+ wp_enqueue_style( self::$sOptionPrefix.'plugin_css' );
731
+ }
732
+
733
+ protected function redirect( $insUrl, $innTimeout = 1 ) {
734
+ echo '
735
+ <script type="text/javascript">
736
+ function redirect() {
737
+ window.location = "'.$insUrl.'";
738
+ }
739
+ var oTimer = setTimeout( "redirect()", "'.($innTimeout * 1000).'" );
740
+ </script>';
741
+ }
742
+
743
+ /**
744
+ * Displays a message in the plugins listing when a plugin has an update available.
745
+ * @param string $insPlugin
746
+ */
747
+ public function onWpPluginUpdateMessage() {
748
+ echo '<div style="color: #dd3333;">'
749
+ .$this->getPluginsListUpdateMessage()
750
+ . '</div>';
751
+ }
752
+
753
+ protected function getPluginsListUpdateMessage() {
754
+ return '';
755
+ }
756
+
757
+ /**
758
+ * Hooked to 'deactivate_plugin' and can be used to interrupt the deactivation of this plugin.
759
+ * @param string $insPlugin
760
+ */
761
+ public function onWpHookDeactivatePlugin( $insPlugin ) {
762
+ if ( strpos( $insPlugin, $this->m_sPluginName ) !== false ) {
763
+ $this->doPreventDeactivation( $insPlugin );
764
+ }
765
+ }
766
+
767
+ /**
768
+ * @param string $insPlugin - the path to the plugin file
769
+ */
770
+ protected function doPreventDeactivation( $insPlugin ) {
771
+ if ( !$this->hasPermissionToSubmit() ) {
772
+ wp_die( 'Sorry, you do not have permission to disable this plugin. You need to authenticate first.' );
773
+ }
774
+ }
775
+
776
+ /**
777
+ * Gets the WordPress option based on this object's option prefix.
778
+ * @param string $insKey
779
+ * @return mixed
780
+ */
781
+ public function getOption( $insKey ) {
782
+ return get_option( $this->getOptionKey($insKey) );
783
+ }
784
+
785
+ /**
786
+ * @param string $insKey
787
+ * @param mixed $insValue
788
+ * @return boolean
789
+ */
790
+ public function addOption( $insKey, $inmValue ) {
791
+ return add_option( $this->getOptionKey($insKey), $inmValue );
792
+ }
793
+
794
+ /**
795
+ * @param string $insKey
796
+ * @param mixed $inmValue
797
+ * @return boolean
798
+ */
799
+ public function updateOption( $insKey, $inmValue ) {
800
+ return update_option( $this->getOptionKey($insKey), $inmValue );
801
+ }
802
+
803
+ /**
804
+ * @param string $insKey
805
+ * @return boolean
806
+ */
807
+ public function deleteOption( $insKey ) {
808
+ return delete_option( $this->getOptionKey($insKey) );
809
+ }
810
+
811
+ public function getOptionKey( $insKey ) {
812
+ return self::$sOptionPrefix.$insKey;
813
+ }
814
+
815
+ /**
816
+ * Use this to wrap up the function when the PHP process is coming to an end. Call from onWpShudown()
817
+ */
818
+ protected function shutdown() {
819
+
820
+ }
821
+
822
+ /**
823
+ * Hooked to 'shutdown'
824
+ */
825
+ public function onWpShutdown() {
826
+ $this->shutdown();
827
+ }
828
+
829
+ public function onWpActivatePlugin() { }
830
+ public function onWpDeactivatePlugin() { }
831
+ public function onWpUninstallPlugin() { }
832
+
833
+ protected function loadWpFunctions() {
834
+ if ( !isset( $this->m_oWpFunctions ) ) {
835
+ $this->m_oWpFunctions = ICWP_WpFunctions_WPSF::GetInstance();
836
+ }
837
+ }
838
+
839
+ protected function flushCaches() {
840
+ if (function_exists('w3tc_pgcache_flush')) {
841
+ w3tc_pgcache_flush();
842
+ }
843
+ }
844
+
845
+ protected function getImageUrl( $insImage ) {
846
+ return $this->m_sPluginUrl.'resources/images/'.$insImage;
847
+ }
848
+ protected function getCssUrl( $insCss ) {
849
+ return $this->m_sPluginUrl.'resources/css/'.$insCss;
850
+ }
851
+ protected function getJsUrl( $insJs ) {
852
+ return $this->m_sPluginUrl.'resources/js/'.$insJs;
853
+ }
854
+
855
+ /**
856
+ * @param string $insKey
857
+ * @param boolean $infIncludeCookie
858
+ * @return mixed|null
859
+ */
860
+ protected function fetchRequest( $insKey, $infIncludeCookie = true ) {
861
+ $mFetchVal = $this->fetchPost( $insKey );
862
+ if ( is_null( $mFetchVal ) ) {
863
+ $mFetchVal = $this->fetchGet( $insKey );
864
+ if ( is_null( $mFetchVal && $infIncludeCookie ) ) {
865
+ $mFetchVal = $this->fetchCookie( $insKey );
866
+ }
867
+ }
868
+ return $mFetchVal;
869
+ }
870
+ /**
871
+ * @param string $insKey
872
+ * @return mixed|null
873
+ */
874
+ protected function fetchGet( $insKey ) {
875
+ if ( function_exists( 'filter_input' ) && defined( 'INPUT_GET' ) ) {
876
+ return filter_input( INPUT_GET, $insKey );
877
+ }
878
+ return $this->arrayFetch( $_GET, $insKey );
879
+ }
880
+ /**
881
+ * @param string $insKey The $_POST key
882
+ * @return mixed|null
883
+ */
884
+ protected function fetchPost( $insKey ) {
885
+ if ( function_exists( 'filter_input' ) && defined( 'INPUT_POST' ) ) {
886
+ return filter_input( INPUT_POST, $insKey );
887
+ }
888
+ return $this->arrayFetch( $_POST, $insKey );
889
+ }
890
+ /**
891
+ * @param string $insKey The $_POST key
892
+ * @return mixed|null
893
+ */
894
+ protected function fetchCookie( $insKey ) {
895
+ if ( function_exists( 'filter_input' ) && defined( 'INPUT_COOKIE' ) ) {
896
+ return filter_input( INPUT_COOKIE, $insKey );
897
+ }
898
+ return $this->arrayFetch( $_COOKIE, $insKey );
899
+ }
900
+
901
+ /**
902
+ * @param array $inaArray
903
+ * @param string $insKey The array key
904
+ * @return mixed|null
905
+ */
906
+ protected function arrayFetch( &$inaArray, $insKey ) {
907
+ if ( empty( $inaArray ) ) {
908
+ return null;
909
+ }
910
+ if ( !isset( $inaArray[$insKey] ) ) {
911
+ return null;
912
+ }
913
+ return $inaArray[$insKey];
914
+ }
915
+
916
+ /**
917
+ * Performs a wp_die() but lets us do something first.
918
+ */
919
+ protected function doWpDie( $insText = '' ) {
920
+ wp_die( $insText );
921
+ exit();
922
+ }
923
+
924
+ public function onWpAdminBar() {
925
+ $aNodes = $this->getAdminBarNodes();
926
+ foreach( $aNodes as $aNode ) {
927
+ $this->addAdminBarNode( $aNode );
928
+ }
929
+ }
930
+
931
+ protected function getAdminBarNodes() { }
932
+
933
+ protected function addAdminBarNode( $aNode ) {
934
+ global $wp_admin_bar;
935
+
936
+ if ( isset( $aNode['children'] ) ) {
937
+ $aChildren = $aNode['children'];
938
+ unset( $aNode['children'] );
939
+ }
940
+ $wp_admin_bar->add_node( $aNode );
941
+
942
+ if ( !empty($aChildren) ) {
943
+ foreach( $aChildren as $aChild ) {
944
+ $aChild['parent'] = $aNode['id'];
945
+ $this->addAdminBarNode( $aChild );
946
+ }
947
+ }
948
+ }
949
+
950
+ protected function getPluginLogoUrl16() {
951
+ return $this->getImageUrl( 'pluginlogo_16x16.png' );
952
+ }
953
+
954
+ protected function getPluginLogoUrl32() {
955
+ return $this->getImageUrl( 'pluginlogo_32x32.png' );
956
+ }
957
+
958
+ /**
959
+ */
960
+ protected function loadDataProcessor() {
961
+ require_once( dirname(__FILE__) . '/icwp-data-processor.php' );
962
+ }
963
+
964
+ }//CLASS
965
+
966
+ endif;
src/icwp-wpfilesystem.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
- * Version: 2013-09-13_A
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
@@ -17,9 +17,14 @@
17
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
  */
19
 
20
- if ( !class_exists('ICWP_WpFilesystem_WPSF') ):
 
 
21
 
22
- class ICWP_WpFilesystem_WPSF {
 
 
 
23
 
24
  /**
25
  * @var object
@@ -31,16 +36,34 @@ class ICWP_WpFilesystem_WPSF {
31
  */
32
  protected $m_sWpConfigPath = null;
33
 
 
 
 
 
 
 
 
 
 
 
34
  public function __construct() {
35
  $this->initFileSystem();
36
- $this->setWpConfigPath();
 
 
 
 
 
 
 
 
37
  }
38
 
39
  protected function setWpConfigPath() {
40
  $this->m_sWpConfigPath = ABSPATH.'wp-config.php';
41
- if ( !is_file($this->m_sWpConfigPath) ) {
42
  $this->m_sWpConfigPath = ABSPATH.'..'.ICWP_DS.'wp-config.php';
43
- if ( !is_file($this->m_sWpConfigPath) ) {
44
  $this->m_sWpConfigPath = false;
45
  }
46
  }
@@ -123,7 +146,50 @@ class ICWP_WpFilesystem_WPSF {
123
  }
124
  return false;
125
  }
126
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  /**
128
  * @param string $insFilePath
129
  * @return NULL|boolean
@@ -146,39 +212,43 @@ class ICWP_WpFilesystem_WPSF {
146
  }
147
 
148
  /**
 
149
  * @return string|null
150
  */
151
- public function getFileContent( $insFilePath ) {
152
- if ( !file_exists( $insFilePath ) ) {
153
  return null;
154
  }
155
  if ( $this->m_oWpFilesystem ) {
156
- return $this->m_oWpFilesystem->get_contents( $insFilePath );
157
  }
158
  else if ( function_exists('file_get_contents') ) {
159
- return file_get_contents( $insFilePath );
160
  }
161
  return null;
162
  }
163
 
164
  /**
 
 
165
  * @return boolean
166
  */
167
- public function putFileContent( $insFilePath, $insContents ) {
168
  if ( $this->m_oWpFilesystem ) {
169
- return $this->m_oWpFilesystem->put_contents( $insFilePath, $insContents, FS_CHMOD_FILE );
170
  }
171
- else if ( file_put_contents( $insFilePath, $insContents ) === false ) {
172
  return false;
173
  }
174
  return true;
175
  }
176
 
177
  /**
 
178
  * @return boolean
179
  */
180
  public function deleteFile( $insFilePath ) {
181
- if ( !file_exists( $insFilePath ) ) {
182
  return null;
183
  }
184
  if ( $this->m_oWpFilesystem ) {
@@ -188,6 +258,46 @@ class ICWP_WpFilesystem_WPSF {
188
  return unlink( $insFilePath );
189
  }
190
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  }
 
 
 
192
 
 
 
 
 
 
 
 
 
 
 
 
193
  endif;
1
  <?php
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
9
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
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
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
  }
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
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 ) {
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;
src/icwp-wpfunctions.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2013 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * Version: 2013-08-14_A
@@ -17,9 +17,24 @@
17
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
  */
19
 
20
- if ( !class_exists('ICWP_WpFunctions_WPSF') ):
 
 
21
 
22
- class ICWP_WpFunctions_WPSF {
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
  /**
25
  * @var string
@@ -82,7 +97,7 @@ class ICWP_WpFunctions_WPSF {
82
 
83
  // TODO: Handle multisite
84
 
85
- if ( version_compare( $this->getWordPressVersion(), '2.7.9', '<=' ) ) {
86
  return get_option( $insKey );
87
  }
88
 
@@ -90,7 +105,7 @@ class ICWP_WpFunctions_WPSF {
90
  return get_site_transient( $insKey );
91
  }
92
 
93
- if ( version_compare( $this->getWordPressVersion(), '2.9.9', '<=' ) ) {
94
  return apply_filters( 'transient_'.$insKey, get_option( '_transient_'.$insKey ) );
95
  }
96
 
@@ -100,7 +115,7 @@ class ICWP_WpFunctions_WPSF {
100
  /**
101
  * @return string
102
  */
103
- public function getWordPressVersion() {
104
  global $wp_version;
105
 
106
  if ( empty( $this->m_sWpVersion ) ) {
@@ -111,8 +126,45 @@ class ICWP_WpFunctions_WPSF {
111
  $this->m_sWpVersion = $aMatches[1];
112
  }
113
  }
114
- return $this->m_sWpVersion;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  }
116
  }
 
 
 
117
 
 
 
 
 
 
 
 
 
 
 
 
118
  endif;
1
  <?php
2
  /**
3
+ * Copyright (c) 2014 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * Version: 2013-08-14_A
17
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18
  */
19
 
20
+ if ( !class_exists('ICWP_WpFunctions_V3') ):
21
+
22
+ class ICWP_WpFunctions_V3 {
23
 
24
+ /**
25
+ * @var ICWP_WpFunctions_V3
26
+ */
27
+ protected static $oInstance = NULL;
28
+
29
+ /**
30
+ * @return ICWP_WpFunctions_V3
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
97
 
98
  // TODO: Handle multisite
99
 
100
+ if ( version_compare( $this->getWordpressVersion(), '2.7.9', '<=' ) ) {
101
  return get_option( $insKey );
102
  }
103
 
105
  return get_site_transient( $insKey );
106
  }
107
 
108
+ if ( version_compare( $this->getWordpressVersion(), '2.9.9', '<=' ) ) {
109
  return apply_filters( 'transient_'.$insKey, get_option( '_transient_'.$insKey ) );
110
  }
111
 
115
  /**
116
  * @return string
117
  */
118
+ public function getWordpressVersion() {
119
  global $wp_version;
120
 
121
  if ( empty( $this->m_sWpVersion ) ) {
126
  $this->m_sWpVersion = $aMatches[1];
127
  }
128
  }
129
+ return empty( $this->m_sWpVersion )? $wp_version : $this->m_sWpVersion;
130
+ }
131
+
132
+ /**
133
+ * @param string $sParams
134
+ */
135
+ public function redirectToLogin( $sParams = '' ) {
136
+ header( "Location: ".site_url().'/wp-login.php'.$sParams );
137
+ exit();
138
+ }
139
+ /**
140
+ */
141
+ public function redirectToAdmin() {
142
+ $this->doRedirect( is_multisite()? get_admin_url() : admin_url() );
143
+ }
144
+ /**
145
+ */
146
+ public function redirectToHome() {
147
+ $this->doRedirect( home_url() );
148
+ }
149
+
150
+ public function doRedirect( $sUrl ) {
151
+ wp_safe_redirect( $sUrl );
152
+ exit();
153
  }
154
  }
155
+ endif;
156
+
157
+ if ( !class_exists('ICWP_WpFunctions_WPSF') ):
158
 
159
+ class ICWP_WpFunctions_WPSF extends ICWP_WpFunctions_V3 {
160
+ /**
161
+ * @return ICWP_WpFunctions_WPSF
162
+ */
163
+ public static function GetInstance() {
164
+ if ( is_null( self::$oInstance ) ) {
165
+ self::$oInstance = new self();
166
+ }
167
+ return self::$oInstance;
168
+ }
169
+ }
170
  endif;
src/icwp-wpsf-stats.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ if ( !class_exists('ICWP_Stats_WPSF') ):
19
+
20
+ class ICWP_Stats_WPSF {
21
+
22
+ const Stats_Key = 'icwp_wpsf_stats';
23
+
24
+ /**
25
+ * @var array
26
+ */
27
+ private static $aStats;
28
+
29
+ public function __construct() { }
30
+
31
+ /**
32
+ * @param $sKey
33
+ */
34
+ public static function DoStatIncrement( $sKey ) {
35
+ self::LoadStats();
36
+ self::$aStats[$sKey] = isset( self::$aStats[$sKey] )? self::$aStats[$sKey] + 1 : 1;
37
+ self::SaveStats();
38
+ }
39
+
40
+ /**
41
+ * The provided key is an array, and the value to count is the key of the array that should be incremented.
42
+ *
43
+ * @param $sKey
44
+ * @param $sValueToCount
45
+ */
46
+ public static function DoStatIncrementKeyValue( $sKey, $sValueToCount ) {
47
+ self::LoadStats();
48
+ if ( !isset( self::$aStats[$sKey] ) || !is_array( self::$aStats[$sKey] ) ) {
49
+ self::$aStats[$sKey] = array();
50
+ }
51
+ self::$aStats[$sKey][$sValueToCount] = isset( self::$aStats[$sKey][$sValueToCount] )? self::$aStats[$sKey][$sValueToCount] + 1 : 1;
52
+ self::SaveStats();
53
+ }
54
+
55
+ /**
56
+ */
57
+ protected static function LoadStats() {
58
+ if ( isset( self::$aStats ) ) {
59
+ return;
60
+ }
61
+ self::$aStats = get_option( self::Stats_Key );
62
+ if ( !is_array( self::$aStats ) ) {
63
+ self::$aStats = array();
64
+ self::SaveStats();
65
+ }
66
+ }
67
+
68
+ /**
69
+ */
70
+ public static function SaveStats() {
71
+ if ( !empty(self::$aStats) ) {
72
+ update_option( self::Stats_Key, self::$aStats );
73
+ }
74
+ }
75
+ }
76
+
77
+ endif;
views/icwp_options_helper.php CHANGED
@@ -3,8 +3,7 @@
3
  function printOptionsPageHeader( $insSection = '' ) {
4
  $sLinkedIcwp = '<a href="http://icwp.io/3a" target="_blank">iControlWP</a>';
5
  echo '<div class="page-header">';
6
- echo '<a href="http://icwp.io/2k" target="_blank"><div class="icon32" id="icontrolwp-icon"><br /></div></a>';
7
- echo '<h2>';
8
  $sBaseTitle = sprintf( _wpsf__( 'WordPress Simple Firewall (from %s)' ), $sLinkedIcwp );
9
  if ( !empty($insSection) ) {
10
  echo sprintf( '%s :: %s', $insSection, $sBaseTitle );
@@ -23,8 +22,7 @@ function printAllPluginOptionsForm( $inaAllPluginOptions, $insVarPrefix = '', $i
23
 
24
  $iRowWidth = 8; //8 spans.
25
  $iOptionWidth = $iRowWidth / $iOptionsPerRow;
26
- $sOptionValue;
27
-
28
  //Take each Options Section in turn
29
  foreach ( $inaAllPluginOptions as $sOptionSection ) {
30
 
@@ -67,13 +65,13 @@ function printAllPluginOptionsForm( $inaAllPluginOptions, $insVarPrefix = '', $i
67
  </div>
68
  ';
69
 
70
- }//foreach section
71
 
72
  }//printAllPluginOptionsForm
73
 
74
  function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
75
 
76
- list( $sOptionKey, $sOptionSaved, $sOptionDefault, $mOptionType, $sOptionHumanName, $sOptionTitle, $sOptionHelpText ) = $inaOption;
77
 
78
  if ( $sOptionKey == 'spacer' ) {
79
  $sHtml = '
@@ -81,19 +79,18 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
81
  </div>
82
  ';
83
  } else {
84
-
 
85
  $sSpanId = 'span_'.$insVarPrefix.$sOptionKey;
86
  $sHtml = '
87
  <div class="span'.$iSpanSize.'" id="'.$sSpanId.'">
88
  <div class="control-group">
89
- <label class="control-label" for="'.$insVarPrefix.$sOptionKey.'">'.$sOptionHumanName.'<br /></label>
90
  <div class="controls">
91
  <div class="option_section'.( ($sOptionSaved == 'Y')? ' selected_item':'' ).'" id="option_section_'.$insVarPrefix.$sOptionKey.'">
92
  <label>
93
  ';
94
  $sAdditionalClass = '';
95
- $sTextInput = '';
96
- $sChecked = '';
97
  $sHelpSection = '';
98
 
99
  if ( $mOptionType === 'checkbox' ) {
@@ -108,8 +105,6 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
108
  class="'.$sAdditionalClass.'"
109
  id="'.$insVarPrefix.$sOptionKey.'" />
110
  '.$sOptionTitle;
111
-
112
- $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
113
 
114
  }
115
  else if ( $mOptionType === 'text' ) {
@@ -122,9 +117,6 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
122
  placeholder="'.$sTextInput.'"
123
  id="'.$insVarPrefix.$sOptionKey.'"
124
  class="span5" />';
125
-
126
- $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
127
-
128
  }
129
  else if ( $mOptionType === 'password' ) {
130
  $sTextInput = esc_attr( $sOptionSaved );
@@ -136,8 +128,6 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
136
  placeholder="'.$sTextInput.'"
137
  id="'.$insVarPrefix.$sOptionKey.'"
138
  class="span5" />';
139
-
140
- $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
141
  }
142
  else if ( $mOptionType === 'email' ) {
143
  $sTextInput = esc_attr( $sOptionSaved );
@@ -149,32 +139,60 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
149
  placeholder="'.$sTextInput.'"
150
  id="'.$insVarPrefix.$sOptionKey.'"
151
  class="span5" />';
152
-
153
- $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
154
-
155
  }
156
  else if ( is_array($mOptionType) ) { //it's a select, or radio
157
-
158
- $sInputType = array_shift($mOptionType);
159
 
160
- if ( $sInputType == 'select' ) {
161
- $sHtml .= '<p>'.$sOptionTitle.'</p>
162
- <select id="'.$insVarPrefix.$sOptionKey.'" name="'.$insVarPrefix.$sOptionKey.'">';
163
  }
164
-
165
- foreach( $mOptionType as $aInput ) {
166
-
167
- $sHtml .= '
168
- <option value="'.$aInput[0].'" id="'.$insVarPrefix.$sOptionKey.'_'.$aInput[0].'"' . (( $sOptionSaved == $aInput[0] )? ' selected="selected"' : '') .'>'. $aInput[1].'</option>';
169
  }
170
-
171
- if ($sInputType == 'select') {
172
- $sHtml .= '
173
- </select>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  }
175
-
176
- $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
177
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  }
179
  else if ( $mOptionType === 'ip_addresses' ) {
180
  $sTextInput = esc_attr( $sOptionSaved );
@@ -187,11 +205,11 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
187
  id="'.$insVarPrefix.$sOptionKey.'"
188
  rows="'.$nRows.'"
189
  class="span5">'.$sTextInput.'</textarea>';
190
-
191
  $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
192
-
193
  }
194
- else if ( $mOptionType === 'comma_separated_lists' ) {
195
  $sTextInput = esc_attr( $sOptionSaved );
196
  $nRows = substr_count( $sTextInput, "\n" ) + 1;
197
  $sHtml .= '
@@ -202,8 +220,21 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
202
  id="'.$insVarPrefix.$sOptionKey.'"
203
  rows="'.$nRows.'"
204
  class="span5">'.$sTextInput.'</textarea>';
205
-
206
  $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  }
208
  else if ( $mOptionType === 'integer' ) {
209
  $sTextInput = esc_attr( $sOptionSaved );
@@ -215,16 +246,22 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
215
  placeholder="'.$sTextInput.'"
216
  id="'.$insVarPrefix.$sOptionKey.'"
217
  class="span5" />';
218
-
219
- $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
220
  }
221
  else {
222
  $sHtml .= 'we should never reach this point';
223
  }
 
 
 
 
 
224
 
 
 
225
  $sHtml .= '
226
  </label>
227
  '.$sOptionHelpText.'
 
228
  </div>
229
  </div><!-- controls -->'
230
  .$sHelpSection.'
@@ -234,4 +271,4 @@ function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
234
  }
235
 
236
  return $sHtml;
237
- }//getPluginOptionSpan
3
  function printOptionsPageHeader( $insSection = '' ) {
4
  $sLinkedIcwp = '<a href="http://icwp.io/3a" target="_blank">iControlWP</a>';
5
  echo '<div class="page-header">';
6
+ echo '<h2><a id="pluginlogo_32" class="header-icon32" href="http://icwp.io/2k" target="_blank"></a>';
 
7
  $sBaseTitle = sprintf( _wpsf__( 'WordPress Simple Firewall (from %s)' ), $sLinkedIcwp );
8
  if ( !empty($insSection) ) {
9
  echo sprintf( '%s :: %s', $insSection, $sBaseTitle );
22
 
23
  $iRowWidth = 8; //8 spans.
24
  $iOptionWidth = $iRowWidth / $iOptionsPerRow;
25
+
 
26
  //Take each Options Section in turn
27
  foreach ( $inaAllPluginOptions as $sOptionSection ) {
28
 
65
  </div>
66
  ';
67
 
68
+ }
69
 
70
  }//printAllPluginOptionsForm
71
 
72
  function getPluginOptionSpan( $inaOption, $iSpanSize, $insVarPrefix = '' ) {
73
 
74
+ list( $sOptionKey, $sOptionSaved, $sOptionDefault, $mOptionType, $sOptionHumanName, $sOptionTitle, $sOptionHelpText, $sHelpLink ) = array_pad( $inaOption, 8, '' );
75
 
76
  if ( $sOptionKey == 'spacer' ) {
77
  $sHtml = '
79
  </div>
80
  ';
81
  } else {
82
+
83
+ $sHelpLink = !empty($sHelpLink)? '<span>['.$sHelpLink.']</span>' : '';
84
  $sSpanId = 'span_'.$insVarPrefix.$sOptionKey;
85
  $sHtml = '
86
  <div class="span'.$iSpanSize.'" id="'.$sSpanId.'">
87
  <div class="control-group">
88
+ <label class="control-label" for="'.$insVarPrefix.$sOptionKey.'">'.$sOptionHumanName.'<br />'.$sHelpLink.'</label>
89
  <div class="controls">
90
  <div class="option_section'.( ($sOptionSaved == 'Y')? ' selected_item':'' ).'" id="option_section_'.$insVarPrefix.$sOptionKey.'">
91
  <label>
92
  ';
93
  $sAdditionalClass = '';
 
 
94
  $sHelpSection = '';
95
 
96
  if ( $mOptionType === 'checkbox' ) {
105
  class="'.$sAdditionalClass.'"
106
  id="'.$insVarPrefix.$sOptionKey.'" />
107
  '.$sOptionTitle;
 
 
108
 
109
  }
110
  else if ( $mOptionType === 'text' ) {
117
  placeholder="'.$sTextInput.'"
118
  id="'.$insVarPrefix.$sOptionKey.'"
119
  class="span5" />';
 
 
 
120
  }
121
  else if ( $mOptionType === 'password' ) {
122
  $sTextInput = esc_attr( $sOptionSaved );
128
  placeholder="'.$sTextInput.'"
129
  id="'.$insVarPrefix.$sOptionKey.'"
130
  class="span5" />';
 
 
131
  }
132
  else if ( $mOptionType === 'email' ) {
133
  $sTextInput = esc_attr( $sOptionSaved );
139
  placeholder="'.$sTextInput.'"
140
  id="'.$insVarPrefix.$sOptionKey.'"
141
  class="span5" />';
142
+
 
 
143
  }
144
  else if ( is_array($mOptionType) ) { //it's a select, or radio
 
 
145
 
146
+ if ( isset( $mOptionType['type'] ) ) {
147
+ $sInputType = $mOptionType['type'];
148
+ unset( $mOptionType['type'] );
149
  }
150
+ else {
151
+ $sInputType = array_shift($mOptionType);
 
 
 
152
  }
153
+
154
+ if ( $sInputType == 'select' ) {
155
+
156
+ $sFragment = '<p>'.$sOptionTitle.'</p>
157
+ <select
158
+ id="'.$insVarPrefix.$sOptionKey.'"
159
+ name="'.$insVarPrefix.$sOptionKey.'">';
160
+
161
+ foreach( $mOptionType as $aInput ) {
162
+
163
+ list( $mOptionValue, $sOptionName ) = $aInput;
164
+ $fSelected = $sOptionSaved == $mOptionValue;
165
+
166
+ $sFragment .= '
167
+ <option
168
+ value="'.$mOptionValue.'"
169
+ id="'.$insVarPrefix.$sOptionKey.'_'.$mOptionValue.'"'
170
+ .( $fSelected? ' selected="selected"' : '') .'>'. $sOptionName.'</option>';
171
+ }
172
+ $sFragment .= '</select>';
173
+
174
  }
175
+ if ( $sInputType == 'multiple_select' ) {
176
+
177
+ $sFragment = '<p>'.$sOptionTitle.'</p>
178
+ <select
179
+ id="'.$insVarPrefix.$sOptionKey.'"
180
+ name="'.$insVarPrefix.$sOptionKey.'[]" multiple multiple="multiple" size="'.count($mOptionType).'">';
181
+
182
+ foreach( $mOptionType as $mOptionValue => $sOptionName ) {
183
+
184
+ $fSelected = in_array( $mOptionValue, $sOptionSaved );
185
+
186
+ $sFragment .= '
187
+ <option
188
+ value="'.$mOptionValue.'"
189
+ id="'.$insVarPrefix.$sOptionKey.'_'.$mOptionValue.'"'
190
+ .( $fSelected? ' selected="selected"' : '') .'>'. $sOptionName.'</option>';
191
+ }
192
+ $sFragment .= '</select>';
193
+ }
194
+
195
+ $sHtml .= $sFragment;
196
  }
197
  else if ( $mOptionType === 'ip_addresses' ) {
198
  $sTextInput = esc_attr( $sOptionSaved );
205
  id="'.$insVarPrefix.$sOptionKey.'"
206
  rows="'.$nRows.'"
207
  class="span5">'.$sTextInput.'</textarea>';
208
+
209
  $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
210
+
211
  }
212
+ else if ( $mOptionType === 'yubikey_unique_keys' ) {
213
  $sTextInput = esc_attr( $sOptionSaved );
214
  $nRows = substr_count( $sTextInput, "\n" ) + 1;
215
  $sHtml .= '
220
  id="'.$insVarPrefix.$sOptionKey.'"
221
  rows="'.$nRows.'"
222
  class="span5">'.$sTextInput.'</textarea>';
223
+
224
  $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
225
+
226
+ }
227
+ else if ( $mOptionType === 'comma_separated_lists' ) {
228
+ $sTextInput = esc_attr( $sOptionSaved );
229
+ $nRows = substr_count( $sTextInput, "\n" ) + 1;
230
+ $sHtml .= '
231
+ <p>'.$sOptionTitle.'</p>
232
+ <textarea type="text"
233
+ name="'.$insVarPrefix.$sOptionKey.'"
234
+ placeholder="'.$sTextInput.'"
235
+ id="'.$insVarPrefix.$sOptionKey.'"
236
+ rows="'.$nRows.'"
237
+ class="span5">'.$sTextInput.'</textarea>';
238
  }
239
  else if ( $mOptionType === 'integer' ) {
240
  $sTextInput = esc_attr( $sOptionSaved );
246
  placeholder="'.$sTextInput.'"
247
  id="'.$insVarPrefix.$sOptionKey.'"
248
  class="span5" />';
 
 
249
  }
250
  else {
251
  $sHtml .= 'we should never reach this point';
252
  }
253
+
254
+ // $sOptionHelpText = '<p class="help-block">'
255
+ // .$sOptionHelpText
256
+ // .( isset($sHelpLink)? '<br /><span class="help-link">['.$sHelpLink.']</span>':'' )
257
+ // .'</p>';
258
 
259
+ $sOptionHelpText = '<p class="help-block">'.$sOptionHelpText.'</p>';
260
+
261
  $sHtml .= '
262
  </label>
263
  '.$sOptionHelpText.'
264
+ <div style="clear:both"></div>
265
  </div>
266
  </div><!-- controls -->'
267
  .$sHelpSection.'
271
  }
272
 
273
  return $sHtml;
274
+ }
views/icwp_wpsf_config_autoupdates_index.php CHANGED
@@ -5,11 +5,25 @@ include_once( dirname(__FILE__).ICWP_DS.'widgets'.ICWP_DS.'icwp_widgets.php' );
5
  <div class="wrap">
6
  <div class="bootstrap-wpadmin">
7
  <?php echo printOptionsPageHeader( _wpsf__('Auto WordPress Updates') ); ?>
8
-
9
  <div class="row">
10
  <div class="<?php echo $icwp_fShowAds? 'span9' : 'span12'; ?>">
11
 
12
  <form action="<?php echo $icwp_form_action; ?>" method="post" class="form-horizontal">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  <?php
14
  wp_nonce_field( $icwp_nonce_field );
15
  printAllPluginOptionsForm( $icwp_aAllOptions, $icwp_var_prefix, 1 );
5
  <div class="wrap">
6
  <div class="bootstrap-wpadmin">
7
  <?php echo printOptionsPageHeader( _wpsf__('Auto WordPress Updates') ); ?>
8
+
9
  <div class="row">
10
  <div class="<?php echo $icwp_fShowAds? 'span9' : 'span12'; ?>">
11
 
12
  <form action="<?php echo $icwp_form_action; ?>" method="post" class="form-horizontal">
13
+ <legend>Run Updates Now</legend>
14
+ <div class="control-group">
15
+ <label class="control-label">Run Automatic Updates
16
+ <br /><span>[<a target="_blank" href="http://icwp.io/44">more info</a>]</span>
17
+ </label>
18
+ <div class="controls">
19
+ <div id="icwp_wpsf_force_run_autoupdates" class="option_section selected_item active">
20
+ <a class="btn btn-warning" href="<?php echo $icwp_form_action; ?>&force_run_auto_updates=now&_wpnonce=<?php echo wp_create_nonce($icwp_nonce_field); ?>&icwp_link_action=1">
21
+ <?php echo _wpsf__('Force Run Automatic Updates Now').' &rarr;';?>
22
+ </a>
23
+ <p class="help-block">WordPress Automatic Updates runs twice daily, but you can run it now on-demand.</p>
24
+ </div>
25
+ </div><!-- controls -->
26
+ </div>
27
  <?php
28
  wp_nonce_field( $icwp_nonce_field );
29
  printAllPluginOptionsForm( $icwp_aAllOptions, $icwp_var_prefix, 1 );
views/icwp_wpsf_config_login_protect_index.php CHANGED
@@ -18,6 +18,7 @@ include_once( dirname(__FILE__).ICWP_DS.'widgets'.ICWP_DS.'icwp_widgets.php' );
18
  <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
19
  <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
20
  <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
 
21
  </div>
22
  </form>
23
 
18
  <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
19
  <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
20
  <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
21
+ <button type="submit" class="btn btn-warning" name="terminate-all-logins" value="1" style="margin-left: 15px"><?php _wpsf_e( 'Clear All Verified Logins' ); ?></button>
22
  </div>
23
  </form>
24
 
views/icwp_wpsf_config_privacy_protect_index.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
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
+ <div class="wrap">
6
+ <div class="bootstrap-wpadmin">
7
+ <?php echo printOptionsPageHeader( _wpsf__('Privacy Protect') ); ?>
8
+
9
+ <div class="row">
10
+ <div class="<?php echo $icwp_fShowAds? 'span9' : 'span12'; ?>">
11
+
12
+ <form action="<?php echo $icwp_form_action; ?>" method="post" class="form-horizontal">
13
+ <?php
14
+ wp_nonce_field( $icwp_nonce_field );
15
+ printAllPluginOptionsForm( $icwp_aAllOptions, $icwp_var_prefix, 1 );
16
+ ?>
17
+ <div class="form-actions">
18
+ <input type="hidden" name="<?php echo $icwp_var_prefix; ?>all_options_input" value="<?php echo $icwp_all_options_input; ?>" />
19
+ <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
20
+ <button type="submit" class="btn btn-primary" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
21
+ </div>
22
+ </form>
23
+
24
+ </div><!-- / span9 -->
25
+
26
+ <?php if ( $icwp_fShowAds ) : ?>
27
+ <div class="span3" id="side_widgets">
28
+ <?php echo getWidgetIframeHtml('side-widgets-wtb'); ?>
29
+ </div>
30
+ <?php endif; ?>
31
+ </div><!-- / row -->
32
+
33
+ </div><!-- / bootstrap-wpadmin -->
34
+ <?php include_once( dirname(__FILE__).'/include_js.php' ); ?>
35
+ </div>
views/icwp_wpsf_firewall_log_index.php CHANGED
@@ -2,7 +2,6 @@
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
  $sPluginName = 'WordPress Simple Firewall';
5
-
6
  $aLogTypes = array(
7
  0 => _wpsf__('Info'),
8
  1 => _wpsf__('Warning'),
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
  $sPluginName = 'WordPress Simple Firewall';
 
5
  $aLogTypes = array(
6
  0 => _wpsf__('Info'),
7
  1 => _wpsf__('Warning'),
views/icwp_wpsf_index.php CHANGED
@@ -2,13 +2,14 @@
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
  $sPluginName = 'WordPress Simple Firewall';
 
5
  $fFirewallOn = $icwp_aMainOptions['enable_firewall'] == 'Y';
6
  $fLoginProtectOn = $icwp_aMainOptions['enable_login_protect'] == 'Y';
7
  $fCommentsFilteringOn = $icwp_aMainOptions['enable_comments_filter'] == 'Y';
8
  $fLockdownOn = $icwp_aMainOptions['enable_lockdown'] == 'Y';
9
  $fAutoUpdatesOn = $icwp_aMainOptions['enable_autoupdates'] == 'Y';
10
 
11
- $sLatestVersionBranch = '2.0.x';
12
  $sOn = _wpsf__( 'On' );
13
  $sOff = _wpsf__( 'Off' );
14
  ?>
@@ -17,11 +18,20 @@ $sOff = _wpsf__( 'Off' );
17
  <div class="bootstrap-wpadmin">
18
  <?php echo printOptionsPageHeader( 'Dashboard' ); ?>
19
 
20
- <?php include_once( dirname(__FILE__).'/widgets/icwp_common_widgets.php' ); ?>
21
-
 
 
 
 
 
 
 
22
  <div class="row">
23
  <div class="<?php echo $icwp_fShowAds? 'span9' : 'span12'; ?>">
24
-
 
 
25
  <form action="<?php echo $icwp_form_action; ?>" method="post" class="form-horizontal">
26
  <?php
27
  wp_nonce_field( $icwp_nonce_field );
@@ -43,19 +53,14 @@ $sOff = _wpsf__( 'Off' );
43
  <?php endif; ?>
44
  </div><!-- / row -->
45
 
46
- <?php if ( $icwp_fShowAds ) : ?>
47
- <div class="row" id="worpit_promo">
48
- <div class="span12">
49
- <?php echo getWidgetIframeHtml( 'dashboard-widget-worpit-wtb' ); ?>
50
- </div>
51
- </div><!-- / row -->
52
 
53
- <div class="row" id="developer_channel_promo">
54
- <div class="span12">
55
- <?php echo getWidgetIframeHtml('dashboard-widget-developerchannel-wtb'); ?>
56
- </div>
57
- </div><!-- / row -->
58
-
59
  <?php endif; ?>
60
 
61
  <div class="row" id="tbs_docs">
@@ -141,7 +146,7 @@ $sOff = _wpsf__( 'Off' );
141
  <?php endif; ?>
142
  <hr/>
143
  <h4 style="margin-top:20px;">
144
- <?php printf( _wpsf__('Login Protection is %s'), $fCommentsFilteringOn ? $sOn : $sOff ); ?>
145
  [ <a href="admin.php?page=icwp-wpsf-comments_filter"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
146
  <?php if ( $fCommentsFilteringOn ) : ?>
147
  <ul>
@@ -177,7 +182,7 @@ $sOff = _wpsf__( 'Off' );
177
  }
178
  ?>
179
  <ul>
180
- <li><?php printf( _wpsf__('Automatically Update WordPress Simple Firewall Plugin: %s'), ($icwp_aAutoUpdatesOptions['autoupdate_plugin_wpsf'] == 'Y')? $sOn : $sOff ); ?></li>
181
  <li><?php printf( _wpsf__('Automatically Update WordPress Core: %s'), $sAutoCoreUpdateOption ); ?></li>
182
  <li><?php printf( _wpsf__('Automatically Update Plugins: %s'), ($icwp_aAutoUpdatesOptions['enable_autoupdate_plugins'] == 'Y')? $sOn : $sOff ); ?></li>
183
  <li><?php printf( _wpsf__('Automatically Update Themes: %s'), ($icwp_aAutoUpdatesOptions['enable_autoupdate_themes'] == 'Y')? $sOn : $sOff ); ?></li>
@@ -194,6 +199,13 @@ $sOff = _wpsf__( 'Off' );
194
  <p><?php printf( _wpsf__('%snew%s refers to the absolute latest release.'), '<span class="label">', '</span>' ) ; ?></p>
195
  <?php
196
  $aNewLog = array(
 
 
 
 
 
 
 
197
  'ADDED: Localization capabilities. All we need now are translators.',
198
  'ADDED: Option to mask the WordPress version so the real version is never publicly visible.'
199
  );
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
  $sPluginName = 'WordPress Simple Firewall';
5
+ $fAdminAccessOn = $icwp_aMainOptions['enable_admin_access_restriction'] == 'Y';
6
  $fFirewallOn = $icwp_aMainOptions['enable_firewall'] == 'Y';
7
  $fLoginProtectOn = $icwp_aMainOptions['enable_login_protect'] == 'Y';
8
  $fCommentsFilteringOn = $icwp_aMainOptions['enable_comments_filter'] == 'Y';
9
  $fLockdownOn = $icwp_aMainOptions['enable_lockdown'] == 'Y';
10
  $fAutoUpdatesOn = $icwp_aMainOptions['enable_autoupdates'] == 'Y';
11
 
12
+ $sLatestVersionBranch = '2.x.x';
13
  $sOn = _wpsf__( 'On' );
14
  $sOff = _wpsf__( 'Off' );
15
  ?>
18
  <div class="bootstrap-wpadmin">
19
  <?php echo printOptionsPageHeader( 'Dashboard' ); ?>
20
 
21
+ <?php if ( $icwp_fShowAds ) : ?>
22
+ <div class="row" id="worpit_promo">
23
+ <div class="span12">
24
+ <?php echo getWidgetIframeHtml( 'dashboard-widget-worpit-wtb' ); ?>
25
+ </div>
26
+ </div><!-- / row -->
27
+
28
+ <?php endif; ?>
29
+
30
  <div class="row">
31
  <div class="<?php echo $icwp_fShowAds? 'span9' : 'span12'; ?>">
32
+
33
+ <?php include_once( dirname(__FILE__).'/icwp_wpsf_state_summary.php' ); ?>
34
+
35
  <form action="<?php echo $icwp_form_action; ?>" method="post" class="form-horizontal">
36
  <?php
37
  wp_nonce_field( $icwp_nonce_field );
53
  <?php endif; ?>
54
  </div><!-- / row -->
55
 
56
+ <?php include_once( dirname(__FILE__).'/widgets/icwp_common_widgets.php' ); ?>
 
 
 
 
 
57
 
58
+ <?php if ( $icwp_fShowAds ) : ?>
59
+ <div class="row" id="developer_channel_promo">
60
+ <div class="span12">
61
+ <?php echo getWidgetIframeHtml('dashboard-widget-developerchannel-wtb'); ?>
62
+ </div>
63
+ </div><!-- / row -->
64
  <?php endif; ?>
65
 
66
  <div class="row" id="tbs_docs">
146
  <?php endif; ?>
147
  <hr/>
148
  <h4 style="margin-top:20px;">
149
+ <?php printf( _wpsf__('Comments Filtering is %s'), $fCommentsFilteringOn ? $sOn : $sOff ); ?>
150
  [ <a href="admin.php?page=icwp-wpsf-comments_filter"><?php _wpsf_e('Configure Now'); ?></a> ]</h4>
151
  <?php if ( $fCommentsFilteringOn ) : ?>
152
  <ul>
182
  }
183
  ?>
184
  <ul>
185
+ <li><?php printf( _wpsf__('Automatically Update WordPress Simple Firewall Plugin: %s'), ($icwp_aAutoUpdatesOptions['autoupdate_plugin_self'] == 'Y')? $sOn : $sOff ); ?></li>
186
  <li><?php printf( _wpsf__('Automatically Update WordPress Core: %s'), $sAutoCoreUpdateOption ); ?></li>
187
  <li><?php printf( _wpsf__('Automatically Update Plugins: %s'), ($icwp_aAutoUpdatesOptions['enable_autoupdate_plugins'] == 'Y')? $sOn : $sOff ); ?></li>
188
  <li><?php printf( _wpsf__('Automatically Update Themes: %s'), ($icwp_aAutoUpdatesOptions['enable_autoupdate_themes'] == 'Y')? $sOn : $sOff ); ?></li>
199
  <p><?php printf( _wpsf__('%snew%s refers to the absolute latest release.'), '<span class="label">', '</span>' ) ; ?></p>
200
  <?php
201
  $aNewLog = array(
202
+ 'ADDED: Options to automatic updates to control where and whether email notifications are sent.',
203
+ 'ADDED: Various fixes and verification of WordPress 3.8 compatibility.',
204
+ 'ADDED: Integration with iControlWP and the automatic updates system.',
205
+ 'ADDED: Better filesystem handling methods.',
206
+ 'ADDED: Better firewall logic for whitelisting rules.',
207
+ 'ADDED: Some new firewall white listing parameters to help with post editing.',
208
+ 'ADDED: Option to run automatic updates upon demand according to your settings',
209
  'ADDED: Localization capabilities. All we need now are translators.',
210
  'ADDED: Option to mask the WordPress version so the real version is never publicly visible.'
211
  );
views/icwp_wpsf_privacy_protect_log_index.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
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
+ $icwp_fShowAds = false;
6
+ ?>
7
+ <style>
8
+ dt {
9
+ width: auto !important;
10
+ }
11
+ tr.row-log-header td {
12
+ border-top: 2px solid #999 !important;
13
+ }
14
+ td .cell-section {
15
+ display: inline-block;
16
+ }
17
+ td .section-timestamp {
18
+ text-align: right;
19
+ width: 28%;
20
+ }
21
+ </style>
22
+
23
+ <div class="wrap">
24
+ <div class="bootstrap-wpadmin">
25
+ <?php echo printOptionsPageHeader( _wpsf__('Privacy Log') ); ?>
26
+
27
+ <div class="row">
28
+ <div class="<?php echo $icwp_fShowAds? 'span9' : 'span12'; ?>">
29
+ <form action="<?php echo $icwp_form_action; ?>" method="post" class="form-horizontal">
30
+ <?php
31
+ wp_nonce_field( $icwp_nonce_field );
32
+ ?>
33
+ <div class="form-actions">
34
+ <input type="hidden" name="icwp_plugin_form_submit" value="Y" />
35
+ <button type="submit" class="btn btn-primary" name="clear_log_submit"><?php _wpsf_e( 'Clear/Fix Log' ); ?></button>
36
+ </div>
37
+ </form>
38
+
39
+ <?php if ( !$icwp_urlrequests_log ) : ?>
40
+ <?php echo 'There are currently no logs to display. If you expect there to be some, use the button above to Clean/Fix them.'; ?>
41
+ <?php else : ?>
42
+
43
+ <table class="table table-bordered table-hover table-condensed">
44
+ <tr>
45
+ <th><?php _wpsf_e('Date'); ?></th>
46
+ <th><?php _wpsf_e('URL'); ?></th>
47
+ <th><?php _wpsf_e('Method'); ?></th>
48
+ <th><?php _wpsf_e('Data'); ?></th>
49
+ <th><?php _wpsf_e('Error?'); ?></th>
50
+ </tr>
51
+ <?php foreach( $icwp_urlrequests_log as $sId => $aLogData ) : ?>
52
+ <tr class="row-log-header">
53
+ <td>
54
+ <span class="cell-section section-timestamp"><?php echo date( 'Y/m/d H:i:s', $aLogData['requested_at'] ); ?></span>
55
+ </td>
56
+ <td><?php echo $aLogData['request_url']; ?></td>
57
+ <td><?php echo $aLogData['request_method']; ?></td>
58
+ <td>
59
+ <dl class="dl-horizontal">
60
+ <?php
61
+ $aArgs = unserialize( $aLogData['request_args'] );
62
+ foreach( $aArgs as $sKey => $mValue ) {
63
+ echo sprintf( '<dt>%s</dt><dd>%s&nbsp;</dd>', $sKey, is_scalar( $mValue )? esc_attr( urldecode($mValue) ) : print_r( $mValue, true ) );
64
+ }
65
+ ?>
66
+ </dl>
67
+ </td>
68
+ <td><?php echo $aLogData['is_error']; ?></td>
69
+ </tr>
70
+ <?php endforeach; ?>
71
+ </table>
72
+
73
+ <?php endif; ?>
74
+ </div><!-- / span9 -->
75
+
76
+ <?php if ( $icwp_fShowAds ) : ?>
77
+ <div class="span3" id="side_widgets">
78
+ <?php echo getWidgetIframeHtml('side-widgets-wtb'); ?>
79
+ </div>
80
+ <?php endif; ?>
81
+ </div><!-- / row -->
82
+
83
+ <div class="row">
84
+ <div class="span6">
85
+ </div><!-- / span6 -->
86
+ <div class="span6">
87
+ <p></p>
88
+ </div><!-- / span6 -->
89
+ </div><!-- / row -->
90
+
91
+ </div><!-- / bootstrap-wpadmin -->
92
+
93
+ </div><!-- / wrap -->
views/icwp_wpsf_state_summary.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( empty($icwp_aSummaryData) ) {
3
+ return;
4
+ }
5
+ $fAdminAccessOn = $icwp_aMainOptions['enable_admin_access_restriction'] == 'Y';
6
+ $fFirewallOn = $icwp_aMainOptions['enable_firewall'] == 'Y';
7
+ $fLoginProtectOn = $icwp_aMainOptions['enable_login_protect'] == 'Y';
8
+ $fCommentsFilteringOn = $icwp_aMainOptions['enable_comments_filter'] == 'Y';
9
+ $fLockdownOn = $icwp_aMainOptions['enable_lockdown'] == 'Y';
10
+ $fAutoUpdatesOn = $icwp_aMainOptions['enable_autoupdates'] == 'Y';
11
+
12
+ $sOn = _wpsf__( 'On' );
13
+ $sOff = _wpsf__( 'Off' );
14
+
15
+ $sInnerSpanSize = 'span4';
16
+
17
+ function printFeatureSummaryBlock( $fOn, $sName, $sSettingsHref= '', $sInnerSpanSize = 4 ) {
18
+ $sFeatureSummaryBlockNameTemplates = '%s : <span class="feature-enabled-text">%s</span>';
19
+ $sOn = _wpsf__( 'On' );
20
+ $sOff = _wpsf__( 'Off' );
21
+ ?>
22
+ <div class="span<?php echo $sInnerSpanSize;?> feature-summary-block state-<?php echo strtolower( $fOn? $sOn : $sOff ); ?>"
23
+ id="feature-<?php echo str_replace( ' ', '', strtolower($sName) ); ?>"
24
+ >
25
+ <div class="row-fluid">
26
+ <div class="feature-icon span3">
27
+ </div>
28
+ <div class="span8 offset1">
29
+ <a class="btn btn-<?php echo $fOn?'success':'warning';?>"
30
+ <?php echo empty($sSettingsHref)? 'disabled="disabled"': sprintf('href="%s"',$sSettingsHref);?>>
31
+ <?php echo empty($sSettingsHref)? _wpsf_e('See Below') : _wpsf_e('Go To Settings');?>
32
+ </a>
33
+ </div>
34
+ </div>
35
+ <div class="feature-name">
36
+ <?php echo sprintf( $sFeatureSummaryBlockNameTemplates, $sName, $fOn? 'ON':'OFF' ); ?>
37
+ </div>
38
+ </div>
39
+ <?php
40
+ }
41
+
42
+ ?>
43
+ <style>
44
+ .feature-summary-blocks {
45
+ }
46
+ .feature-summary-blocks .feature-summary-block {
47
+ background-color: #F6F6F6;
48
+ border: 1px solid rgba(0, 0, 0, 0.3);
49
+ border-radius: 3px;
50
+ margin-bottom: 20px;
51
+ padding: 0;
52
+ }
53
+ .feature-summary-blocks .feature-summary-block.state-on {
54
+ background-color: rgba( 102, 216, 45, 0.2 );
55
+ }
56
+ .feature-summary-blocks .feature-summary-block.state-off {
57
+ background-color: rgba( 239, 141, 49, 0.2 );
58
+ }
59
+ .feature-summary-blocks .feature-summary-block .row-fluid .feature-icon {
60
+ padding: 20px;
61
+ text-align: center;
62
+ }
63
+ .feature-summary-blocks .feature-summary-block .row-fluid div {
64
+ line-height: 46px;
65
+ padding: 20px;
66
+ text-align: center;
67
+ }
68
+ .feature-summary-blocks .feature-summary-block .feature-icon a {
69
+ margin-left: 53px;
70
+ }
71
+ .feature-summary-blocks .feature-summary-block .feature-name {
72
+ border-top: 1px dashed #999999;
73
+ padding: 5px 20px;
74
+ }
75
+ .feature-summary-blocks .feature-summary-block .feature-name .feature-enabled-text {
76
+ float: right;
77
+ }
78
+ .feature-summary-blocks .feature-summary-block .feature-icon:before {
79
+ -webkit-font-smoothing: antialiased;
80
+ display: inline-block;
81
+ font: 48px/1 'dashicons';
82
+ vertical-align: top;
83
+ }
84
+ #feature-adminaccessprotection .feature-icon:before {
85
+ content: "\f332";
86
+ }
87
+ #feature-firewall .feature-icon:before {
88
+ content: "\f479";
89
+ }
90
+ #feature-loginprotection .feature-icon:before {
91
+ content: "\f110";
92
+ }
93
+ #feature-commentsfilter .feature-icon:before {
94
+ content: "\f130";
95
+ }
96
+ #feature-autoupdates .feature-icon:before {
97
+ content: "\f463";
98
+ }
99
+ #feature-lockdown .feature-icon:before {
100
+ content: "\f160";
101
+ }
102
+
103
+ </style>
104
+
105
+ <div class="row-fluid feature-summary-blocks">
106
+ <?php
107
+ foreach( $icwp_aSummaryData as $nKey => $aSummary ) {
108
+ if ( $nKey > 0 && ($nKey % 3 == 0) ) {
109
+ echo '</div><div class="row-fluid feature-summary-blocks">';
110
+ }
111
+ $sPage = isset( $_GET['page'] )? $_GET['page'] : '';
112
+ printFeatureSummaryBlock( $aSummary[0], $aSummary[1], ( $sPage==$aSummary[2])? '' : network_admin_url( 'admin.php?page='.$aSummary[2] ) );
113
+ }
114
+ ?>
115
+ </div>
views/widgets/icwp_widgets.php CHANGED
@@ -1,28 +1,26 @@
1
  <?php
2
-
3
  function getWidgetIframeHtml( $insSnippet ) {
4
-
5
  $sSubPageNow = isset( $_GET['page'] )? 'page='.$_GET['page'].'&': '';
6
-
7
  $sWidth = '100%';
8
- $sBackgroundColor = "#ffffff";
9
  $sIframeName = 'iframe-hlt-bootstrapcss-'.$insSnippet;
10
-
11
  if ( strpos( $insSnippet, 'side-widgets') !== false ) {
12
- $sHeight = '800px';
13
  }
14
  elseif ( strpos( $insSnippet, 'dashboard-widget-developerchannel') !== false ) {
15
  $sHeight = '312px';
16
  }
17
  elseif ( strpos( $insSnippet, 'dashboard-widget-worpit') !== false ) {
18
  $sHeight = '230px';
19
- $sBackgroundColor = 'whiteSmoke';
20
  }
21
-
22
  return '<iframe name="'.$sIframeName.'"
23
- src="http://www.hostliketoast.com/custom/remote/plugins/hlt-bootstrapcss-plugin-widgets.php?'.$sSubPageNow.'snippet='.$insSnippet.'"
24
  width="'.$sWidth.'" height="'.$sHeight.'" frameborder="0" scrolling="no" style="background-color:'.$sBackgroundColor.';" ></iframe>
25
  ';
26
-
27
- }//getWidgetIframeHtml
28
- ?>
1
  <?php
 
2
  function getWidgetIframeHtml( $insSnippet ) {
3
+
4
  $sSubPageNow = isset( $_GET['page'] )? 'page='.$_GET['page'].'&': '';
5
+
6
  $sWidth = '100%';
7
+ $sBackgroundColor = "rgba(0, 0, 0, 0)";
8
  $sIframeName = 'iframe-hlt-bootstrapcss-'.$insSnippet;
9
+
10
  if ( strpos( $insSnippet, 'side-widgets') !== false ) {
11
+ $sHeight = '1200px';
12
  }
13
  elseif ( strpos( $insSnippet, 'dashboard-widget-developerchannel') !== false ) {
14
  $sHeight = '312px';
15
  }
16
  elseif ( strpos( $insSnippet, 'dashboard-widget-worpit') !== false ) {
17
  $sHeight = '230px';
18
+ $sBackgroundColor = 'whiteSmoke';
19
  }
20
+
21
  return '<iframe name="'.$sIframeName.'"
22
+ src="http://www.icontrolwp.com/custom/remote/plugins/hlt-bootstrapcss-plugin-widgets.php?'.$sSubPageNow.'snippet='.$insSnippet.'"
23
  width="'.$sWidth.'" height="'.$sHeight.'" frameborder="0" scrolling="no" style="background-color:'.$sBackgroundColor.';" ></iframe>
24
  ';
25
+
26
+ }