Shield Security for WordPress - Version 6.10.0

Version Description

  • Current Release = Released: 15th October, 2018 - Release Notes
Download this release

Release Info

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

Code changes from version 6.9.4 to 6.10.0

Files changed (91) hide show
  1. icwp-plugin-controller.php +49 -23
  2. icwp-wpsf.php +1 -1
  3. languages/default.mo +0 -0
  4. languages/default.po +669 -510
  5. languages/wp-simple-firewall-pt_BR.mo +0 -0
  6. plugin-spec.php +9 -9
  7. readme.txt +21 -39
  8. resources/css/global-plugin.css +6 -0
  9. resources/css/plugin.css +1 -1
  10. resources/images/pluginlogo_banner-772x250.png +0 -0
  11. resources/images/shield/SHIELDSECURITY.png +0 -0
  12. resources/js/global-plugin.js +223 -100
  13. src/common/easydigitaldownloads/ICWP_EDD_LicenseVO.php +4 -2
  14. src/common/icwp-data.php +24 -4
  15. src/common/icwp-foundation.php +23 -1
  16. src/common/icwp-optionsvo.php +28 -8
  17. src/common/icwp-serviceproviders.php +455 -0
  18. src/common/icwp-usermeta.php +2 -2
  19. src/common/icwp-wpfunctions-plugins.php +8 -7
  20. src/common/lib/composer.lock +5 -5
  21. src/common/lib/vendor/composer/installed.json +57 -57
  22. src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/ru.php +7 -7
  23. src/common/lib/vendor/nesbot/carbon/src/JsonSerializable.php +15 -13
  24. src/common/wp-users.php +1 -5
  25. src/config/feature-admin_access_restriction.php +212 -197
  26. src/config/feature-audit_trail.php +112 -112
  27. src/config/feature-autoupdates.php +2 -1
  28. src/config/feature-comments_filter.php +175 -177
  29. src/config/feature-email.php +1 -1
  30. src/config/feature-firewall.php +219 -181
  31. src/config/feature-hack_protect.php +2 -1
  32. src/config/feature-headers.php +138 -136
  33. src/config/feature-insights.php +2 -1
  34. src/config/feature-ips.php +4 -1
  35. src/config/feature-license.php +2 -1
  36. src/config/feature-lockdown.php +92 -90
  37. src/config/feature-login_protect.php +16 -0
  38. src/config/feature-plugin.php +3 -8
  39. src/config/feature-sessions.php +4 -1
  40. src/config/feature-statistics.php +2 -1
  41. src/config/feature-traffic.php +14 -2
  42. src/config/feature-user_management.php +143 -146
  43. src/features/admin_access_restriction.php +69 -46
  44. src/features/autoupdates.php +1 -1
  45. src/features/base.php +1 -0
  46. src/features/base_wpsf.php +46 -9
  47. src/features/firewall.php +11 -3
  48. src/features/hack_protect.php +1 -13
  49. src/features/license.php +6 -4
  50. src/features/login_protect.php +92 -17
  51. src/features/plugin.php +52 -0
  52. src/features/traffic.php +22 -0
  53. src/processors/admin_access_restriction.php +134 -46
  54. src/processors/adminaccess_whitelabel.php +1 -1
  55. src/processors/autoupdates.php +2 -13
  56. src/processors/base.php +1 -1
  57. src/processors/base_wpsf.php +22 -22
  58. src/processors/basedb.php +34 -4
  59. src/processors/comments_filter.php +1 -1
  60. src/processors/email.php +2 -2
  61. src/processors/firewall.php +16 -40
  62. src/processors/hackprotect_ptguard.php +0 -1
  63. src/processors/ips.php +17 -33
  64. src/processors/login_protect.php +1 -1
  65. src/processors/loginprotect_backupcodes.php +209 -0
  66. src/processors/loginprotect_gasp.php +4 -1
  67. src/processors/loginprotect_googleauthenticator.php +6 -58
  68. src/processors/loginprotect_intent.php +114 -69
  69. src/processors/loginprotect_intentprovider_base.php +59 -6
  70. src/processors/loginprotect_track.php +16 -1
  71. src/processors/loginprotect_twofactorauth.php +38 -30
  72. src/processors/loginprotect_wplogin.php +1 -1
  73. src/processors/loginprotect_yubikey.php +6 -4
  74. src/processors/plugin.php +32 -2
  75. src/processors/sessions.php +28 -24
  76. src/processors/traffic_logger.php +34 -179
  77. src/query/base/select.php +9 -6
  78. src/query/sessions/ICWP_WPSF_SessionVO.php +17 -3
  79. src/query/sessions/insert.php +12 -10
  80. src/query/sessions/select.php +5 -5
  81. src/query/sessions/update.php +41 -10
  82. src/wizards/base_wpsf.php +1 -1
  83. src/wizards/login_protect.php +4 -2
  84. src/wizards/plugin.php +1 -1
  85. templates/php/page/login_intent.php +3 -3
  86. templates/php/snippets/gasp_js.php +8 -1
  87. templates/php/snippets/plugin-deactivate-survey.php +13 -0
  88. templates/php/snippets/user_profile_backupcode.php +47 -0
  89. templates/twig/pages/base.twig +1 -1
  90. templates/twig/wizard/slides/mfa/authemail.twig +7 -2
  91. templates/twig/wpadmin_pages/insights/index.twig +3 -3
icwp-plugin-controller.php CHANGED
@@ -289,13 +289,14 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
289
  add_action( 'wp_ajax_nopriv_'.$this->prefix(), array( $this, 'ajaxAction' ) );
290
  }
291
 
 
292
  add_filter( 'all_plugins', array( $this, 'filter_hidePluginFromTableList' ) );
293
  add_filter( 'all_plugins', array( $this, 'doPluginLabels' ) );
294
- add_filter( 'plugin_action_links_'.$this->getPluginBaseFile(), array( $this, 'onWpPluginActionLinks' ), 50, 1 );
295
  add_filter( 'plugin_row_meta', array( $this, 'onPluginRowMeta' ), 50, 2 );
296
  add_filter( 'site_transient_update_plugins', array( $this, 'filter_hidePluginUpdatesFromUI' ) );
297
- add_action( 'in_plugin_update_message-'.$this->getPluginBaseFile(), array( $this, 'onWpPluginUpdateMessage' ) );
298
-
299
  add_filter( 'auto_update_plugin', array( $this, 'onWpAutoUpdate' ), 500, 2 );
300
  add_filter( 'set_site_transient_update_plugins', array( $this, 'setUpdateFirstDetectedAt' ) );
301
 
@@ -416,7 +417,9 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
416
  $sAction = $this->loadWpUsers()->isUserLoggedIn() ? 'ajaxAuthAction' : 'ajaxNonAuthAction';
417
  ob_start();
418
  $aResponseData = apply_filters( $this->prefix( $sAction ), array() );
419
- $aResponseData = apply_filters( $this->prefix( 'ajaxAction' ), $aResponseData );
 
 
420
  $sNoise = ob_get_clean();
421
 
422
  if ( is_array( $aResponseData ) && isset( $aResponseData[ 'success' ] ) ) {
@@ -587,11 +590,11 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
587
 
588
  $sShow = $aLink[ 'show' ];
589
  $bShow = ( $sShow == 'always' ) || ( $bPro && $sShow == 'pro' ) || ( !$bPro && $sShow == 'free' );
590
- if ( !$oDP->validUrl( $aLink[ 'href' ] ) && method_exists( $this, $aLink[ 'href' ] ) ) {
591
  $aLink[ 'href' ] = $this->{$aLink[ 'href' ]}();
592
  }
593
 
594
- if ( !$bShow || !$oDP->validUrl( $aLink[ 'href' ] )
595
  || empty( $aLink[ 'name' ] ) || empty( $aLink[ 'href' ] ) ) {
596
  continue;
597
  }
@@ -627,25 +630,23 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
627
  public function onWpEnqueueAdminJs() {
628
  $sVers = $this->getVersion();
629
 
630
- if ( $this->isValidAdminArea() ) {
631
- $aAdminJs = $this->getPluginSpec_Include( 'admin' );
632
- if ( isset( $aAdminJs[ 'js' ] ) && !empty( $aAdminJs[ 'js' ] ) && is_array( $aAdminJs[ 'js' ] ) ) {
633
- $sDep = false;
634
- foreach ( $aAdminJs[ 'css' ] as $sAsset ) {
635
- $sUrl = $this->getPluginUrl_Js( $sAsset.'.js' );
636
- if ( !empty( $sUrl ) ) {
637
- $sUnique = $this->prefix( $sAsset );
638
- wp_register_script( $sUnique, $sUrl, $sDep ? array( $sDep ) : array(), $sVers );
639
- wp_enqueue_script( $sUnique );
640
- $sDep = $sUnique;
641
- }
642
  }
643
  }
644
  }
645
 
646
  if ( $this->getIsPage_PluginAdmin() ) {
647
  $aAdminJs = $this->getPluginSpec_Include( 'plugin_admin' );
648
- if ( isset( $aAdminJs[ 'js' ] ) && !empty( $aAdminJs[ 'js' ] ) && is_array( $aAdminJs[ 'js' ] ) ) {
649
  $sDep = false;
650
  foreach ( $aAdminJs[ 'js' ] as $sAsset ) {
651
 
@@ -674,7 +675,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
674
 
675
  if ( $this->isValidAdminArea() ) {
676
  $aAdminCss = $this->getPluginSpec_Include( 'admin' );
677
- if ( isset( $aAdminCss[ 'css' ] ) && !empty( $aAdminCss[ 'css' ] ) && is_array( $aAdminCss[ 'css' ] ) ) {
678
  $sDependent = false;
679
  foreach ( $aAdminCss[ 'css' ] as $sCssAsset ) {
680
  $sUrl = $this->getPluginUrl_Css( $sCssAsset.'.css' );
@@ -690,7 +691,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
690
 
691
  if ( $this->getIsPage_PluginAdmin() ) {
692
  $aAdminCss = $this->getPluginSpec_Include( 'plugin_admin' );
693
- if ( isset( $aAdminCss[ 'css' ] ) && !empty( $aAdminCss[ 'css' ] ) && is_array( $aAdminCss[ 'css' ] ) ) {
694
  $sDependent = false;
695
  foreach ( $aAdminCss[ 'css' ] as $sCssAsset ) {
696
  $sUrl = $this->getPluginUrl_Css( $sCssAsset.'.css' );
@@ -716,7 +717,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
716
  }
717
  else {
718
  $sMessage = sprintf(
719
- '<div class="%s plugin_update_message">%s</div>',
720
  $this->getPluginPrefix(),
721
  $sMessage
722
  );
@@ -724,6 +725,22 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
724
  echo $sMessage;
725
  }
726
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
727
  /**
728
  * This will hook into the saving of plugin update information and if there is an update for this plugin, it'll add
729
  * a data stamp to state when the update was first detected.
@@ -781,6 +798,15 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
781
  $sAutoupdateSpec = 'yes'; // so that we appear to be automatically updating
782
  }
783
 
 
 
 
 
 
 
 
 
 
784
  switch ( $sAutoupdateSpec ) {
785
 
786
  case 'yes' :
@@ -843,7 +869,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
843
  $oDP = $this->loadDP();
844
  foreach ( array( '16x16', '32x32', '128x128' ) as $sSize ) {
845
  $sKey = 'icon_url_'.$sSize;
846
- if ( !empty( $aLabels[ $sKey ] ) && !$oDP->validUrl( $aLabels[ $sKey ] ) ) {
847
  $aLabels[ $sKey ] = $this->getPluginUrl_Image( $aLabels[ $sKey ] );
848
  }
849
  }
289
  add_action( 'wp_ajax_nopriv_'.$this->prefix(), array( $this, 'ajaxAction' ) );
290
  }
291
 
292
+ $sBaseFile = $this->getPluginBaseFile();
293
  add_filter( 'all_plugins', array( $this, 'filter_hidePluginFromTableList' ) );
294
  add_filter( 'all_plugins', array( $this, 'doPluginLabels' ) );
295
+ add_filter( 'plugin_action_links_'.$sBaseFile, array( $this, 'onWpPluginActionLinks' ), 50, 1 );
296
  add_filter( 'plugin_row_meta', array( $this, 'onPluginRowMeta' ), 50, 2 );
297
  add_filter( 'site_transient_update_plugins', array( $this, 'filter_hidePluginUpdatesFromUI' ) );
298
+ add_action( 'in_plugin_update_message-'.$sBaseFile, array( $this, 'onWpPluginUpdateMessage' ) );
299
+ add_filter( 'site_transient_update_plugins', array( $this, 'blockIncompatibleUpdates' ) );
300
  add_filter( 'auto_update_plugin', array( $this, 'onWpAutoUpdate' ), 500, 2 );
301
  add_filter( 'set_site_transient_update_plugins', array( $this, 'setUpdateFirstDetectedAt' ) );
302
 
417
  $sAction = $this->loadWpUsers()->isUserLoggedIn() ? 'ajaxAuthAction' : 'ajaxNonAuthAction';
418
  ob_start();
419
  $aResponseData = apply_filters( $this->prefix( $sAction ), array() );
420
+ if ( empty( $aResponseData ) ) {
421
+ $aResponseData = apply_filters( $this->prefix( 'ajaxAction' ), $aResponseData );
422
+ }
423
  $sNoise = ob_get_clean();
424
 
425
  if ( is_array( $aResponseData ) && isset( $aResponseData[ 'success' ] ) ) {
590
 
591
  $sShow = $aLink[ 'show' ];
592
  $bShow = ( $sShow == 'always' ) || ( $bPro && $sShow == 'pro' ) || ( !$bPro && $sShow == 'free' );
593
+ if ( !$oDP->isValidUrl( $aLink[ 'href' ] ) && method_exists( $this, $aLink[ 'href' ] ) ) {
594
  $aLink[ 'href' ] = $this->{$aLink[ 'href' ]}();
595
  }
596
 
597
+ if ( !$bShow || !$oDP->isValidUrl( $aLink[ 'href' ] )
598
  || empty( $aLink[ 'name' ] ) || empty( $aLink[ 'href' ] ) ) {
599
  continue;
600
  }
630
  public function onWpEnqueueAdminJs() {
631
  $sVers = $this->getVersion();
632
 
633
+ $aAdminJs = $this->getPluginSpec_Include( 'admin' );
634
+ if ( !empty( $aAdminJs[ 'js' ] ) && is_array( $aAdminJs[ 'js' ] ) ) {
635
+ $sDep = false;
636
+ foreach ( $aAdminJs[ 'css' ] as $sAsset ) {
637
+ $sUrl = $this->getPluginUrl_Js( $sAsset.'.js' );
638
+ if ( !empty( $sUrl ) ) {
639
+ $sUnique = $this->prefix( $sAsset );
640
+ wp_register_script( $sUnique, $sUrl, $sDep ? array( $sDep ) : array(), $sVers );
641
+ wp_enqueue_script( $sUnique );
642
+ $sDep = $sUnique;
 
 
643
  }
644
  }
645
  }
646
 
647
  if ( $this->getIsPage_PluginAdmin() ) {
648
  $aAdminJs = $this->getPluginSpec_Include( 'plugin_admin' );
649
+ if ( !empty( $aAdminJs[ 'js' ] ) && is_array( $aAdminJs[ 'js' ] ) ) {
650
  $sDep = false;
651
  foreach ( $aAdminJs[ 'js' ] as $sAsset ) {
652
 
675
 
676
  if ( $this->isValidAdminArea() ) {
677
  $aAdminCss = $this->getPluginSpec_Include( 'admin' );
678
+ if ( !empty( $aAdminCss[ 'css' ] ) && is_array( $aAdminCss[ 'css' ] ) ) {
679
  $sDependent = false;
680
  foreach ( $aAdminCss[ 'css' ] as $sCssAsset ) {
681
  $sUrl = $this->getPluginUrl_Css( $sCssAsset.'.css' );
691
 
692
  if ( $this->getIsPage_PluginAdmin() ) {
693
  $aAdminCss = $this->getPluginSpec_Include( 'plugin_admin' );
694
+ if ( !empty( $aAdminCss[ 'css' ] ) && is_array( $aAdminCss[ 'css' ] ) ) {
695
  $sDependent = false;
696
  foreach ( $aAdminCss[ 'css' ] as $sCssAsset ) {
697
  $sUrl = $this->getPluginUrl_Css( $sCssAsset.'.css' );
717
  }
718
  else {
719
  $sMessage = sprintf(
720
+ ' <span class="%s plugin_update_message">%s</span>',
721
  $this->getPluginPrefix(),
722
  $sMessage
723
  );
725
  echo $sMessage;
726
  }
727
 
728
+ /**
729
+ * We protect against providing updates for Shield v7.0.0
730
+ * @param stdClass $oUpdates
731
+ * @return stdClass
732
+ */
733
+ public function blockIncompatibleUpdates( $oUpdates ) {
734
+ $sFile = $this->getPluginBaseFile();
735
+ if ( !empty( $oUpdates->response ) && isset( $oUpdates->response[ $sFile ] ) ) {
736
+ if ( version_compare( $oUpdates->response[ $sFile ]->new_version, '7.0.0', '>=' )
737
+ && !$this->loadDP()->getPhpVersionIsAtLeast( '5.3.0' ) ) {
738
+ unset( $oUpdates->response[ $sFile ] );
739
+ }
740
+ }
741
+ return $oUpdates;
742
+ }
743
+
744
  /**
745
  * This will hook into the saving of plugin update information and if there is an update for this plugin, it'll add
746
  * a data stamp to state when the update was first detected.
798
  $sAutoupdateSpec = 'yes'; // so that we appear to be automatically updating
799
  }
800
 
801
+ $sNewVersion = $oWpPlugins->getUpdateNewVersion( $sFile );
802
+
803
+ /** We block automatic updates for Shield v7+ if PHP < 5.3 */
804
+ // if ( version_compare( $sNewVersion, '7.0.0', '>=' )
805
+ // && !$this->loadDP()->getPhpVersionIsAtLeast( '5.3' )
806
+ // ) {
807
+ // $sAutoupdateSpec = 'block';
808
+ // }
809
+
810
  switch ( $sAutoupdateSpec ) {
811
 
812
  case 'yes' :
869
  $oDP = $this->loadDP();
870
  foreach ( array( '16x16', '32x32', '128x128' ) as $sSize ) {
871
  $sKey = 'icon_url_'.$sSize;
872
+ if ( !empty( $aLabels[ $sKey ] ) && !$oDP->isValidUrl( $aLabels[ $sKey ] ) ) {
873
  $aLabels[ $sKey ] = $this->getPluginUrl_Image( $aLabels[ $sKey ] );
874
  }
875
  }
icwp-wpsf.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Shield Security
4
  * Plugin URI: https://icwp.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
- * Version: 6.9.4
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages/
9
  * Author: One Dollar Plugin
3
  * Plugin Name: Shield Security
4
  * Plugin URI: https://icwp.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
+ * Version: 6.10.0
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages/
9
  * Author: One Dollar Plugin
languages/default.mo CHANGED
Binary file
languages/default.po CHANGED
@@ -1,8 +1,8 @@
1
  msgid ""
2
  msgstr ""
3
  "Project-Id-Version: WPSF v2.0\n"
4
- "POT-Creation-Date: 2018-09-09 17:40+0100\n"
5
- "PO-Revision-Date: 2018-09-09 17:40+0100\n"
6
  "Last-Translator: \n"
7
  "Language-Team: \n"
8
  "Language: en_GB\n"
@@ -51,23 +51,23 @@ msgstr ""
51
  msgid "Enter your Security Admin Access Key"
52
  msgstr ""
53
 
54
- #: src/features/admin_access_restriction.php:250
55
  msgid "Security Admin key accepted."
56
  msgstr ""
57
 
58
- #: src/features/admin_access_restriction.php:253
59
  msgid "Security Admin key not accepted."
60
  msgstr ""
61
 
62
- #: src/features/admin_access_restriction.php:394
63
  msgid "Security Admin Protection"
64
  msgstr ""
65
 
66
- #: src/features/admin_access_restriction.php:403
67
  msgid "The Security Admin protection is not active."
68
  msgstr ""
69
 
70
- #: src/features/admin_access_restriction.php:407
71
  #: src/features/audit_trail.php:304 src/features/base_wpsf.php:169
72
  #: src/features/base_wpsf.php:209 src/features/hack_protect.php:656
73
  #: src/features/hack_protect.php:677 src/features/hack_protect.php:698
@@ -76,31 +76,31 @@ msgstr ""
76
  msgid "Options"
77
  msgstr ""
78
 
79
- #: src/features/admin_access_restriction.php:408
80
  msgid "Security Admin should be turned-on to protect your security settings."
81
  msgstr ""
82
 
83
- #: src/features/admin_access_restriction.php:438
84
  #: src/features/audit_trail.php:290 src/features/autoupdates.php:186
85
  #: src/features/comments_filter.php:103 src/features/firewall.php:59
86
  #: src/features/hack_protect.php:759 src/features/headers.php:120
87
  #: src/features/ips.php:302 src/features/lockdown.php:85
88
- #: src/features/login_protect.php:536 src/features/sessions.php:51
89
  #: src/features/statistics.php:51 src/features/statistics.php:60
90
- #: src/features/traffic.php:451 src/features/user_management.php:311
91
  #, php-format
92
  msgid "Enable Module: %s"
93
  msgstr ""
94
 
95
- #: src/features/admin_access_restriction.php:440
96
- #: src/features/admin_access_restriction.php:450
97
- #: src/features/admin_access_restriction.php:459
98
- #: src/features/admin_access_restriction.php:469
99
  #: src/features/audit_trail.php:292 src/features/audit_trail.php:301
100
  #: src/features/audit_trail.php:310 src/features/autoupdates.php:188
101
  #: src/features/autoupdates.php:197 src/features/autoupdates.php:206
102
  #: src/features/autoupdates.php:216 src/features/autoupdates.php:226
103
- #: src/features/base_wpsf.php:321 src/features/comments_filter.php:105
104
  #: src/features/comments_filter.php:114 src/features/comments_filter.php:124
105
  #: src/features/comments_filter.php:133 src/features/firewall.php:61
106
  #: src/features/hack_protect.php:754 src/features/hack_protect.php:761
@@ -110,37 +110,37 @@ msgstr ""
110
  #: src/features/headers.php:122 src/features/headers.php:131
111
  #: src/features/headers.php:140 src/features/ips.php:304
112
  #: src/features/ips.php:314 src/features/ips.php:324
113
- #: src/features/license.php:688 src/features/lockdown.php:87
114
  #: src/features/lockdown.php:96 src/features/lockdown.php:105
115
- #: src/features/lockdown.php:114 src/features/login_protect.php:539
116
- #: src/features/login_protect.php:548 src/features/login_protect.php:559
117
- #: src/features/login_protect.php:568 src/features/login_protect.php:577
118
- #: src/features/login_protect.php:587 src/features/login_protect.php:596
119
- #: src/features/login_protect.php:605 src/features/plugin.php:733
120
  #: src/features/plugin.php:740 src/features/plugin.php:755
121
  #: src/features/sessions.php:53 src/features/statistics.php:53
122
  #: src/features/statistics.php:62 src/features/statistics.php:71
123
- #: src/features/traffic.php:453 src/features/traffic.php:462
124
  #: src/features/user_management.php:313 src/features/user_management.php:323
125
  #: src/features/user_management.php:332 src/features/user_management.php:341
126
  #: src/features/user_management.php:350
127
  msgid "Purpose"
128
  msgstr ""
129
 
130
- #: src/features/admin_access_restriction.php:440
131
- #: src/features/admin_access_restriction.php:450
132
  msgid ""
133
  "Restricts access to this plugin preventing unauthorized changes to your "
134
  "security settings."
135
  msgstr ""
136
 
137
- #: src/features/admin_access_restriction.php:441
138
- #: src/features/admin_access_restriction.php:451
139
- #: src/features/admin_access_restriction.php:460
140
  #: src/features/audit_trail.php:293 src/features/audit_trail.php:302
141
  #: src/features/audit_trail.php:311 src/features/autoupdates.php:189
142
  #: src/features/autoupdates.php:198 src/features/autoupdates.php:208
143
- #: src/features/autoupdates.php:217 src/features/base_wpsf.php:322
144
  #: src/features/comments_filter.php:106 src/features/comments_filter.php:115
145
  #: src/features/comments_filter.php:125 src/features/comments_filter.php:134
146
  #: src/features/firewall.php:62 src/features/firewall.php:71
@@ -151,246 +151,247 @@ msgstr ""
151
  #: src/features/hack_protect.php:819 src/features/headers.php:123
152
  #: src/features/headers.php:132 src/features/headers.php:141
153
  #: src/features/ips.php:305 src/features/ips.php:315 src/features/ips.php:325
154
- #: src/features/license.php:689 src/features/lockdown.php:88
155
  #: src/features/lockdown.php:97 src/features/lockdown.php:106
156
- #: src/features/lockdown.php:115 src/features/login_protect.php:540
157
- #: src/features/login_protect.php:549 src/features/login_protect.php:560
158
- #: src/features/login_protect.php:578 src/features/login_protect.php:597
159
- #: src/features/login_protect.php:702 src/features/plugin.php:757
160
  #: src/features/sessions.php:54 src/features/statistics.php:54
161
  #: src/features/statistics.php:63 src/features/statistics.php:72
162
- #: src/features/traffic.php:454 src/features/traffic.php:463
163
  #: src/features/user_management.php:314 src/features/user_management.php:324
164
  #: src/features/user_management.php:333 src/features/user_management.php:342
165
  #: src/features/user_management.php:351
166
  msgid "Recommendation"
167
  msgstr ""
168
 
169
- #: src/features/admin_access_restriction.php:441
170
  #: src/features/audit_trail.php:293 src/features/autoupdates.php:189
171
  #: src/features/comments_filter.php:106 src/features/firewall.php:62
172
  #: src/features/hack_protect.php:762 src/features/hack_protect.php:771
173
  #: src/features/hack_protect.php:781 src/features/hack_protect.php:790
174
  #: src/features/hack_protect.php:799 src/features/ips.php:305
175
  #: src/features/ips.php:315 src/features/lockdown.php:88
176
- #: src/features/login_protect.php:540 src/features/sessions.php:54
177
  #: src/features/statistics.php:54 src/features/statistics.php:63
178
  #: src/features/user_management.php:314
179
  #, php-format
180
  msgid "Keep the %s feature turned on."
181
  msgstr ""
182
 
183
- #: src/features/admin_access_restriction.php:441
184
- #: src/features/admin_access_restriction.php:503 src/features/plugin.php:945
185
  #: src/features/plugin.php:947 src/wizards/base_wpsf.php:65
186
  msgid "Security Admin"
187
  msgstr ""
188
 
189
- #: src/features/admin_access_restriction.php:442
190
  msgid "You need to also enter a new Access Key to enable this feature."
191
  msgstr ""
192
 
193
- #: src/features/admin_access_restriction.php:444
194
  #: src/features/audit_trail.php:295 src/features/autoupdates.php:191
195
  #: src/features/comments_filter.php:108 src/features/firewall.php:64
196
  #: src/features/hack_protect.php:764 src/features/headers.php:125
197
  #: src/features/ips.php:308 src/features/lockdown.php:90
198
- #: src/features/login_protect.php:537 src/features/sessions.php:56
199
  #: src/features/statistics.php:56 src/features/statistics.php:65
200
- #: src/features/traffic.php:456 src/features/user_management.php:316
201
  #, php-format
202
  msgid "%s/%s Module"
203
  msgstr ""
204
 
205
- #: src/features/admin_access_restriction.php:444
206
- #: src/features/admin_access_restriction.php:574
207
  #: src/features/audit_trail.php:295 src/features/autoupdates.php:191
208
  #: src/features/comments_filter.php:108 src/features/firewall.php:64
209
  #: src/features/hack_protect.php:764 src/features/headers.php:125
210
  #: src/features/ips.php:308 src/features/lockdown.php:90
211
- #: src/features/login_protect.php:537 src/features/sessions.php:56
212
  #: src/features/statistics.php:56 src/features/statistics.php:65
213
- #: src/features/traffic.php:456 src/features/user_management.php:316
214
  msgid "Enable"
215
  msgstr ""
216
 
217
- #: src/features/admin_access_restriction.php:444
218
  #: src/features/audit_trail.php:295 src/features/autoupdates.php:191
219
  #: src/features/comments_filter.php:108 src/features/firewall.php:64
220
  #: src/features/hack_protect.php:764 src/features/headers.php:125
221
  #: src/features/ips.php:308 src/features/lockdown.php:90
222
- #: src/features/login_protect.php:537 src/features/sessions.php:56
223
  #: src/features/statistics.php:56 src/features/statistics.php:65
224
- #: src/features/traffic.php:456 src/features/user_management.php:316
225
  msgid "Disable"
226
  msgstr ""
227
 
228
- #: src/features/admin_access_restriction.php:448
229
  msgid "Security Admin Restriction Settings"
230
  msgstr ""
231
 
232
- #: src/features/admin_access_restriction.php:451
233
- #: src/features/admin_access_restriction.php:460
234
  #: src/features/comments_filter.php:115 src/features/comments_filter.php:134
235
- #: src/features/login_protect.php:578 src/features/login_protect.php:597
236
  #: src/features/plugin.php:758 src/features/user_management.php:324
237
  #: src/features/user_management.php:333 src/features/user_management.php:342
238
  #: src/features/user_management.php:351
239
  msgid "Use of this feature is highly recommend."
240
  msgstr ""
241
 
242
- #: src/features/admin_access_restriction.php:453
243
  msgid "Security Admin Settings"
244
  msgstr ""
245
 
246
- #: src/features/admin_access_restriction.php:457
247
  msgid "Security Admin Restriction Zones"
248
  msgstr ""
249
 
250
- #: src/features/admin_access_restriction.php:459
251
  msgid ""
252
  "Restricts access to key WordPress areas for all users not authenticated with "
253
  "the Security Admin Access system."
254
  msgstr ""
255
 
256
- #: src/features/admin_access_restriction.php:462
257
  msgid "Access Restriction Zones"
258
  msgstr ""
259
 
260
- #: src/features/admin_access_restriction.php:466
261
- #: src/features/admin_access_restriction.php:479
262
- #: src/features/admin_access_restriction.php:574
263
  msgid "White Label"
264
  msgstr ""
265
 
266
- #: src/features/admin_access_restriction.php:470
267
  #, php-format
268
  msgid "Rename and re-brand the %s plugin for your client site installations."
269
  msgstr ""
270
 
271
- #: src/features/admin_access_restriction.php:474
272
- #: src/features/login_protect.php:682
 
273
  msgid "Important"
274
  msgstr ""
275
 
276
- #: src/features/admin_access_restriction.php:475
277
  msgid "The Security Admin system must be active for these settings to apply."
278
  msgstr ""
279
 
280
- #: src/features/admin_access_restriction.php:503
281
  #: src/features/audit_trail.php:338 src/features/autoupdates.php:251
282
  #: src/features/comments_filter.php:188 src/features/firewall.php:115
283
  #: src/features/hack_protect.php:842 src/features/headers.php:166
284
  #: src/features/ips.php:347 src/features/lockdown.php:140
285
- #: src/features/login_protect.php:630 src/features/plugin.php:805
286
  #: src/features/sessions.php:79 src/features/statistics.php:99
287
- #: src/features/statistics.php:105 src/features/traffic.php:488
288
  #: src/features/user_management.php:376
289
  #, php-format
290
  msgid "Enable %s Module"
291
  msgstr ""
292
 
293
- #: src/features/admin_access_restriction.php:504
294
  msgid "Enforce Security Admin Access Restriction"
295
  msgstr ""
296
 
297
- #: src/features/admin_access_restriction.php:505
298
  msgid ""
299
  "Enable this with great care and consideration. Ensure that you set a key "
300
  "that you have set an access key that you will remember."
301
  msgstr ""
302
 
303
- #: src/features/admin_access_restriction.php:509
304
  msgid "Security Admin Access Key"
305
  msgstr ""
306
 
307
- #: src/features/admin_access_restriction.php:510
308
  msgid "Provide/Update Security Admin Access Key"
309
  msgstr ""
310
 
311
- #: src/features/admin_access_restriction.php:511
312
- #: src/features/admin_access_restriction.php:532
313
- #: src/features/admin_access_restriction.php:539
314
- #: src/features/admin_access_restriction.php:546
315
- #: src/features/admin_access_restriction.php:552
316
- #: src/features/admin_access_restriction.php:558
317
  msgid "Careful"
318
  msgstr ""
319
 
320
- #: src/features/admin_access_restriction.php:511
321
  msgid ""
322
  "If you forget this, you could potentially lock yourself out from using this "
323
  "plugin."
324
  msgstr ""
325
 
326
- #: src/features/admin_access_restriction.php:512
327
  msgid "Security Key Currently Set"
328
  msgstr ""
329
 
330
- #: src/features/admin_access_restriction.php:512
331
  msgid "Security Key NOT Currently Set"
332
  msgstr ""
333
 
334
- #: src/features/admin_access_restriction.php:513
335
  #, php-format
336
  msgid "To delete the current security key, type exactly \"%s\" and save."
337
  msgstr ""
338
 
339
- #: src/features/admin_access_restriction.php:517
340
  msgid "Security Admin Timeout"
341
  msgstr ""
342
 
343
- #: src/features/admin_access_restriction.php:518
344
  msgid "Specify An Automatic Timeout Interval For Security Admin Access"
345
  msgstr ""
346
 
347
- #: src/features/admin_access_restriction.php:519
348
  msgid "This will automatically expire your Security Admin Session."
349
  msgstr ""
350
 
351
- #: src/features/admin_access_restriction.php:523
352
  #: src/features/hack_protect.php:850 src/features/hack_protect.php:916
353
- #: src/features/login_protect.php:710 src/features/login_protect.php:753
354
- #: src/features/login_protect.php:760 src/features/user_management.php:399
355
  msgid "Default"
356
  msgstr ""
357
 
358
- #: src/features/admin_access_restriction.php:530
359
  msgid "Pages"
360
  msgstr ""
361
 
362
- #: src/features/admin_access_restriction.php:531
363
  msgid "Restrict Access To Key WordPress Posts And Pages Actions"
364
  msgstr ""
365
 
366
- #: src/features/admin_access_restriction.php:532
367
  msgid "This will restrict access to page/post creation, editing and deletion."
368
  msgstr ""
369
 
370
- #: src/features/admin_access_restriction.php:533
371
- #: src/features/admin_access_restriction.php:540
372
- #: src/features/admin_access_restriction.php:561
373
  #: src/features/comments_filter.php:126 src/features/headers.php:239
374
- #: src/features/login_protect.php:550 src/features/login_protect.php:579
375
- #: src/features/login_protect.php:588 src/features/login_protect.php:606
376
- #: src/features/login_protect.php:673 src/features/login_protect.php:681
377
- #: src/features/login_protect.php:695 src/features/plugin.php:759
378
  #: src/features/plugin.php:763 src/features/plugin.php:857
379
  msgid "Note"
380
  msgstr ""
381
 
382
- #: src/features/admin_access_restriction.php:533
383
- #: src/features/admin_access_restriction.php:540
384
- #: src/features/admin_access_restriction.php:563
385
  #, php-format
386
  msgid "Selecting \"%s\" will also restrict all other options."
387
  msgstr ""
388
 
389
- #: src/features/admin_access_restriction.php:533
390
  msgid "Edit"
391
  msgstr ""
392
 
393
- #: src/features/admin_access_restriction.php:537
394
  #: src/features/audit_trail.php:187 src/features/audit_trail.php:362
395
  #: src/features/audit_trail.php:363 src/features/autoupdates.php:282
396
  #: src/features/hack_protect.php:728 src/features/insights.php:330
@@ -398,209 +399,219 @@ msgstr ""
398
  msgid "Plugins"
399
  msgstr ""
400
 
401
- #: src/features/admin_access_restriction.php:538
402
  msgid "Restrict Access To Key WordPress Plugin Actions"
403
  msgstr ""
404
 
405
- #: src/features/admin_access_restriction.php:539
406
  msgid ""
407
  "This will restrict access to plugin installation, update, activation and "
408
  "deletion."
409
  msgstr ""
410
 
411
- #: src/features/admin_access_restriction.php:540
412
- #: src/features/admin_access_restriction.php:566
413
  msgid "Activate"
414
  msgstr ""
415
 
416
- #: src/features/admin_access_restriction.php:544
417
  msgid "WordPress Options"
418
  msgstr ""
419
 
420
- #: src/features/admin_access_restriction.php:545
421
  msgid "Restrict Access To Certain WordPress Admin Options"
422
  msgstr ""
423
 
424
- #: src/features/admin_access_restriction.php:546
425
  msgid ""
426
  "This will restrict the ability of WordPress administrators from changing key "
427
  "WordPress settings."
428
  msgstr ""
429
 
430
- #: src/features/admin_access_restriction.php:550
431
  msgid "Admin Users"
432
  msgstr ""
433
 
434
- #: src/features/admin_access_restriction.php:551
435
  msgid "Restrict Access To Create/Delete/Modify Other Admin Users"
436
  msgstr ""
437
 
438
- #: src/features/admin_access_restriction.php:552
439
  msgid ""
440
  "This will restrict the ability of WordPress administrators from creating, "
441
  "modifying or promoting other administrators."
442
  msgstr ""
443
 
444
- #: src/features/admin_access_restriction.php:556
445
  #: src/features/audit_trail.php:188 src/features/audit_trail.php:368
446
  #: src/features/audit_trail.php:369 src/features/autoupdates.php:294
447
  #: src/features/insights.php:376 src/features/insights.php:387
448
  msgid "Themes"
449
  msgstr ""
450
 
451
- #: src/features/admin_access_restriction.php:557
452
  msgid "Restrict Access To WordPress Theme Actions"
453
  msgstr ""
454
 
455
- #: src/features/admin_access_restriction.php:558
456
  msgid ""
457
  "This will restrict access to theme installation, update, activation and "
458
  "deletion."
459
  msgstr ""
460
 
461
- #: src/features/admin_access_restriction.php:565
462
  #, php-format
463
  msgid "%s and %s"
464
  msgstr ""
465
 
466
- #: src/features/admin_access_restriction.php:567
467
  msgid "Edit Theme Options"
468
  msgstr ""
469
 
470
- #: src/features/admin_access_restriction.php:575
471
  msgid "Activate Your White Label Settings"
472
  msgstr ""
473
 
474
- #: src/features/admin_access_restriction.php:576
475
  msgid "Turn on/off the application of your White Label settings."
476
  msgstr ""
477
 
478
- #: src/features/admin_access_restriction.php:579
479
  msgid "Hide Updates"
480
  msgstr ""
481
 
482
- #: src/features/admin_access_restriction.php:580
483
  msgid "Hide Plugin Updates From Non-Security Admins"
484
  msgstr ""
485
 
486
- #: src/features/admin_access_restriction.php:581
487
  #, php-format
488
  msgid "Hide available %s updates from non-security administrators."
489
  msgstr ""
490
 
491
- #: src/features/admin_access_restriction.php:584
492
- #: src/features/admin_access_restriction.php:591
493
  msgid "Plugin Name"
494
  msgstr ""
495
 
496
- #: src/features/admin_access_restriction.php:585
497
  msgid "The Name Of The Plugin"
498
  msgstr ""
499
 
500
- #: src/features/admin_access_restriction.php:586
501
  msgid "The name of the plugin that will be displayed to your site users."
502
  msgstr ""
503
 
504
- #: src/features/admin_access_restriction.php:589
505
  msgid "Menu Title"
506
  msgstr ""
507
 
508
- #: src/features/admin_access_restriction.php:590
509
  msgid "The Main Menu Title Of The Plugin"
510
  msgstr ""
511
 
512
- #: src/features/admin_access_restriction.php:591
513
  #, php-format
514
  msgid ""
515
  "The Main Menu Title Of The Plugin. If left empty, the \"%s\" will be used."
516
  msgstr ""
517
 
518
- #: src/features/admin_access_restriction.php:594
519
  msgid "Company Name"
520
  msgstr ""
521
 
522
- #: src/features/admin_access_restriction.php:595
523
  msgid "The Name Of Your Company"
524
  msgstr ""
525
 
526
- #: src/features/admin_access_restriction.php:596
527
  msgid "Provide the name of your company."
528
  msgstr ""
529
 
530
- #: src/features/admin_access_restriction.php:599
531
  msgid "Description"
532
  msgstr ""
533
 
534
- #: src/features/admin_access_restriction.php:600
535
  msgid "The Description Of The Plugin"
536
  msgstr ""
537
 
538
- #: src/features/admin_access_restriction.php:601
539
  msgid "The description of the plugin displayed on the plugins page."
540
  msgstr ""
541
 
542
- #: src/features/admin_access_restriction.php:604
543
  msgid "Home URL"
544
  msgstr ""
545
 
546
- #: src/features/admin_access_restriction.php:605
547
  msgid "Plugin Home Page URL"
548
  msgstr ""
549
 
550
- #: src/features/admin_access_restriction.php:606
551
  msgid ""
552
  "When a user clicks the home link for this plugin, this is where they'll be "
553
  "directed."
554
  msgstr ""
555
 
556
- #: src/features/admin_access_restriction.php:609
557
  msgid "Menu Icon"
558
  msgstr ""
559
 
560
- #: src/features/admin_access_restriction.php:610
561
  msgid "Menu Icon URL"
562
  msgstr ""
563
 
564
- #: src/features/admin_access_restriction.php:611
565
  msgid "The URL of the icon to display in the menu."
566
  msgstr ""
567
 
568
- #: src/features/admin_access_restriction.php:612
569
- #: src/features/admin_access_restriction.php:618
570
  #, php-format
571
  msgid "The %s should measure %s."
572
  msgstr ""
573
 
574
- #: src/features/admin_access_restriction.php:612
575
  msgid "icon"
576
  msgstr ""
577
 
578
- #: src/features/admin_access_restriction.php:615
579
  msgid "Dashboard Logo"
580
  msgstr ""
581
 
582
- #: src/features/admin_access_restriction.php:616
583
  msgid "Dashboard Logo URL"
584
  msgstr ""
585
 
586
- #: src/features/admin_access_restriction.php:617
587
  msgid "The URL of the logo to display in the admin pages."
588
  msgstr ""
589
 
590
- #: src/features/admin_access_restriction.php:618
591
  msgid "logo"
592
  msgstr ""
593
 
 
 
 
 
 
 
 
 
 
 
594
  #: src/features/audit_trail.php:139
595
  msgid "Your IP"
596
  msgstr ""
597
 
598
  #: src/features/audit_trail.php:169 src/features/audit_trail.php:183
599
- #: src/features/license.php:93 src/features/plugin.php:950
600
  msgid "Audit Trail Viewer"
601
  msgstr ""
602
 
603
- #: src/features/audit_trail.php:184 src/features/license.php:94
604
  msgid "Review audit trail logs "
605
  msgstr ""
606
 
@@ -634,6 +645,7 @@ msgid "Message"
634
  msgstr ""
635
 
636
  #: src/features/audit_trail.php:195 src/features/user_management.php:157
 
637
  #: src/processors/loginprotect_twofactorauth.php:161
638
  #: src/processors/user_management.php:208
639
  #: src/processors/user_management.php:236
@@ -645,14 +657,15 @@ msgid "Category"
645
  msgstr ""
646
 
647
  #: src/features/audit_trail.php:197 src/features/plugin.php:937
648
- #: src/processors/firewall.php:468
 
649
  #: src/processors/loginprotect_twofactorauth.php:162
650
  #: src/processors/user_management.php:210
651
  #: src/processors/user_management.php:237
652
  msgid "IP Address"
653
  msgstr ""
654
 
655
- #: src/features/audit_trail.php:198 src/features/traffic.php:377
656
  msgid "You"
657
  msgstr ""
658
 
@@ -685,7 +698,7 @@ msgid "Provides finer control over the audit trail itself."
685
  msgstr ""
686
 
687
  #: src/features/audit_trail.php:302 src/features/audit_trail.php:311
688
- #: src/features/traffic.php:463
689
  msgid "These settings are dependent on your requirements."
690
  msgstr ""
691
 
@@ -704,9 +717,9 @@ msgstr ""
704
  #: src/features/audit_trail.php:339 src/features/autoupdates.php:252
705
  #: src/features/firewall.php:116 src/features/hack_protect.php:843
706
  #: src/features/headers.php:167 src/features/ips.php:348
707
- #: src/features/lockdown.php:141 src/features/login_protect.php:631
708
  #: src/features/sessions.php:80 src/features/statistics.php:100
709
- #: src/features/statistics.php:106 src/features/traffic.php:489
710
  #: src/features/user_management.php:377
711
  #, php-format
712
  msgid "Enable (or Disable) The %s Module"
@@ -716,9 +729,9 @@ msgstr ""
716
  #: src/features/comments_filter.php:190 src/features/firewall.php:117
717
  #: src/features/hack_protect.php:844 src/features/headers.php:168
718
  #: src/features/ips.php:349 src/features/lockdown.php:142
719
- #: src/features/login_protect.php:632 src/features/sessions.php:81
720
  #: src/features/statistics.php:101 src/features/statistics.php:107
721
- #: src/features/traffic.php:490 src/features/user_management.php:378
722
  #, php-format
723
  msgid "Un-Checking this option will completely disable the %s module."
724
  msgstr ""
@@ -1100,7 +1113,7 @@ msgstr ""
1100
  #: src/processors/hackprotect_corechecksumscan.php:280
1101
  #: src/processors/hackprotect_pluginvulnerabilities.php:156
1102
  #: src/processors/hackprotect_wpvulnscan.php:147
1103
- #: src/processors/loginprotect_intent.php:282
1104
  msgid "More Info"
1105
  msgstr ""
1106
 
@@ -1179,25 +1192,25 @@ msgstr ""
1179
  msgid "Nonce security checking failed - the nonce supplied was \"%s\"."
1180
  msgstr ""
1181
 
1182
- #: src/features/base_wpsf.php:318 src/features/base_wpsf.php:319
1183
  msgid "User Messages"
1184
  msgstr ""
1185
 
1186
- #: src/features/base_wpsf.php:321
1187
  msgid "Customize the messages displayed to the user."
1188
  msgstr ""
1189
 
1190
- #: src/features/base_wpsf.php:322
1191
  msgid ""
1192
  "Use this section if you need to communicate to the user in a particular "
1193
  "manner."
1194
  msgstr ""
1195
 
1196
- #: src/features/base_wpsf.php:323
1197
  msgid "Hint"
1198
  msgstr ""
1199
 
1200
- #: src/features/base_wpsf.php:323
1201
  #, php-format
1202
  msgid "To reset any message to its default, enter the text exactly: %s"
1203
  msgstr ""
@@ -1256,11 +1269,11 @@ msgstr ""
1256
  msgid "Adds Google reCAPTCHA to the Comment Forms."
1257
  msgstr ""
1258
 
1259
- #: src/features/comments_filter.php:125 src/features/login_protect.php:549
1260
  msgid "Keep this turned on."
1261
  msgstr ""
1262
 
1263
- #: src/features/comments_filter.php:126 src/features/login_protect.php:550
1264
  msgid ""
1265
  "You will need to register for Google reCAPTCHA keys and store them in the "
1266
  "Shield 'Dashboard' settings."
@@ -1431,16 +1444,16 @@ msgstr ""
1431
  msgid "Use Google reCAPTCHA on the comments form to prevent bot-spam comments."
1432
  msgstr ""
1433
 
1434
- #: src/features/comments_filter.php:249 src/features/login_protect.php:686
1435
  #: src/features/plugin.php:907
1436
  msgid "reCAPTCHA Style"
1437
  msgstr ""
1438
 
1439
- #: src/features/comments_filter.php:250 src/features/login_protect.php:687
1440
  msgid "How Google reCAPTCHA Will Be Displayed"
1441
  msgstr ""
1442
 
1443
- #: src/features/comments_filter.php:251 src/features/login_protect.php:688
1444
  #: src/features/plugin.php:909
1445
  msgid ""
1446
  "You can choose the reCAPTCHA display format that best suits your site, "
@@ -1629,7 +1642,7 @@ msgid ""
1629
  "%s, etc)."
1630
  msgstr ""
1631
 
1632
- #: src/features/firewall.php:133 src/processors/firewall.php:536
1633
  msgid "SQL Queries"
1634
  msgstr ""
1635
 
@@ -1642,7 +1655,7 @@ msgstr ""
1642
  msgid "This will block sql in application parameters (e.g. %s, etc)."
1643
  msgstr ""
1644
 
1645
- #: src/features/firewall.php:139 src/processors/firewall.php:530
1646
  msgid "WordPress Terms"
1647
  msgstr ""
1648
 
@@ -1656,7 +1669,7 @@ msgid ""
1656
  "user_login, etc.)."
1657
  msgstr ""
1658
 
1659
- #: src/features/firewall.php:145 src/processors/firewall.php:533
1660
  msgid "Field Truncation"
1661
  msgstr ""
1662
 
@@ -1668,7 +1681,7 @@ msgstr ""
1668
  msgid "This will block field truncation attacks in application parameters."
1669
  msgstr ""
1670
 
1671
- #: src/features/firewall.php:151 src/processors/firewall.php:545
1672
  msgid "PHP Code"
1673
  msgstr ""
1674
 
@@ -1737,7 +1750,7 @@ msgstr ""
1737
  #: src/processors/hackprotect_corechecksumscan.php:244
1738
  #: src/processors/hackprotect_filecleanerscan.php:232
1739
  #: src/processors/hackprotect_pluginvulnerabilities.php:110
1740
- #: src/processors/hackprotect_ptguard.php:491
1741
  #: src/processors/hackprotect_wpvulnscan.php:220
1742
  #: src/processors/loginprotect_wplogin.php:74
1743
  #: src/processors/loginprotect_wplogin.php:93 src/processors/plugin.php:206
@@ -1800,7 +1813,7 @@ msgid "Ignore %s"
1800
  msgstr ""
1801
 
1802
  #: src/features/firewall.php:195 src/features/firewall.php:196
1803
- #: src/features/login_protect.php:180
1804
  msgid "Administrators"
1805
  msgstr ""
1806
 
@@ -1841,7 +1854,7 @@ msgstr ""
1841
  msgid "%s per day"
1842
  msgstr ""
1843
 
1844
- #: src/features/hack_protect.php:618
1845
  msgid "Never"
1846
  msgstr ""
1847
 
@@ -2233,8 +2246,8 @@ msgid ""
2233
  msgstr ""
2234
 
2235
  #: src/features/hack_protect.php:935 src/features/headers.php:197
2236
- #: src/features/headers.php:198 src/features/login_protect.php:646
2237
- #: src/features/login_protect.php:658 src/features/login_protect.php:664
2238
  #: src/features/plugin.php:799
2239
  #, php-format
2240
  msgid "Enable %s"
@@ -2679,12 +2692,12 @@ msgstr ""
2679
  msgid "Pro"
2680
  msgstr ""
2681
 
2682
- #: src/features/insights.php:525 src/features/traffic.php:351
2683
  msgid "Yes"
2684
  msgstr ""
2685
 
2686
- #: src/features/insights.php:525 src/features/traffic.php:327
2687
- #: src/features/traffic.php:351
2688
  msgid "No"
2689
  msgstr ""
2690
 
@@ -2938,96 +2951,100 @@ msgid ""
2938
  "the White List"
2939
  msgstr ""
2940
 
2941
- #: src/features/license.php:96
2942
- msgid "Name"
 
 
 
 
2943
  msgstr ""
2944
 
2945
  #: src/features/license.php:97
2946
- msgid "Active"
2947
  msgstr ""
2948
 
2949
- #: src/features/license.php:98
2950
  msgid "Status"
2951
  msgstr ""
2952
 
2953
- #: src/features/license.php:99
2954
  msgid "Key"
2955
  msgstr ""
2956
 
2957
- #: src/features/license.php:100
2958
  msgid "Expires"
2959
  msgstr ""
2960
 
2961
- #: src/features/license.php:101
2962
  msgid "Owner"
2963
  msgstr ""
2964
 
2965
- #: src/features/license.php:102
2966
  msgid "Checked"
2967
  msgstr ""
2968
 
2969
- #: src/features/license.php:103
2970
  msgid "Error"
2971
  msgstr ""
2972
 
2973
- #: src/features/license.php:174
2974
  #, php-format
2975
  msgid "Please wait %s before attempting another license check."
2976
  msgstr ""
2977
 
2978
- #: src/features/license.php:175
2979
  #, php-format
2980
  msgid "%s second"
2981
  msgid_plural "%s seconds"
2982
  msgstr[0] ""
2983
  msgstr[1] ""
2984
 
2985
- #: src/features/license.php:181
2986
  msgid "Valid license found."
2987
  msgstr ""
2988
 
2989
- #: src/features/license.php:181
2990
  msgid "Valid license couldn't be found."
2991
  msgstr ""
2992
 
2993
- #: src/features/license.php:303
2994
  #, php-format
2995
  msgid "Automatic license verification failed after %s days."
2996
  msgstr ""
2997
 
2998
- #: src/features/license.php:348
2999
  msgid "Attempts to verify Shield Pro license has just failed."
3000
  msgstr ""
3001
 
3002
- #: src/features/license.php:349 src/features/license.php:366
3003
  #, php-format
3004
  msgid "Please check your license on-site: %s"
3005
  msgstr ""
3006
 
3007
- #: src/features/license.php:350 src/features/license.php:367
3008
  #, php-format
3009
  msgid "If this problem persists, please contact support: %s"
3010
  msgstr ""
3011
 
3012
- #: src/features/license.php:365
3013
  msgid "All attempts to verify Shield Pro license have failed."
3014
  msgstr ""
3015
 
3016
- #: src/features/license.php:685 src/features/license.php:686
3017
  msgid "License Options"
3018
  msgstr ""
3019
 
3020
- #: src/features/license.php:688
3021
  #, php-format
3022
  msgid "Activate %s Pro Extensions."
3023
  msgstr ""
3024
 
3025
- #: src/features/license.php:689
3026
  msgid "TODO."
3027
  msgstr ""
3028
 
3029
- #: src/features/license.php:713 src/features/license.php:714
3030
- #: src/features/license.php:715
3031
  msgid "License Key"
3032
  msgstr ""
3033
 
@@ -3230,509 +3247,530 @@ msgstr ""
3230
  msgid "Email verification could not be completed."
3231
  msgstr ""
3232
 
3233
- #: src/features/login_protect.php:101
3234
  msgid ""
3235
  "Before enabling 2-factor email authentication for your WordPress site, you "
3236
  "must verify you can receive this email."
3237
  msgstr ""
3238
 
3239
- #: src/features/login_protect.php:102
3240
  msgid ""
3241
  "This verifies your website can send email and that your account can receive "
3242
  "emails sent from your site."
3243
  msgstr ""
3244
 
3245
- #: src/features/login_protect.php:107
3246
  #, php-format
3247
  msgid "Click the verify link: %s"
3248
  msgstr ""
3249
 
3250
- #: src/features/login_protect.php:110
3251
  #, php-format
3252
  msgid "Here's your code for the guided wizard: %s"
3253
  msgstr ""
3254
 
3255
- #: src/features/login_protect.php:113
3256
  msgid "Email Sending Verification"
3257
  msgstr ""
3258
 
3259
- #: src/features/login_protect.php:176
3260
  msgid "Subscribers"
3261
  msgstr ""
3262
 
3263
- #: src/features/login_protect.php:177
3264
  msgid "Contributors"
3265
  msgstr ""
3266
 
3267
- #: src/features/login_protect.php:178
3268
  msgid "Authors"
3269
  msgstr ""
3270
 
3271
- #: src/features/login_protect.php:179
3272
  msgid "Editors"
3273
  msgstr ""
3274
 
3275
- #: src/features/login_protect.php:437
3276
  msgid "I'm a human."
3277
  msgstr ""
3278
 
3279
- #: src/features/login_protect.php:441
3280
  msgid "Please check the box to show us you're a human."
3281
  msgstr ""
3282
 
3283
- #: src/features/login_protect.php:476
3284
  #, php-format
3285
  msgid "Support for login protection with %s is a Pro-only feature."
3286
  msgstr ""
3287
 
3288
- #: src/features/login_protect.php:482
3289
  msgid ""
3290
  "2FA by email demands that your WP site is properly configured to send email."
3291
  msgstr ""
3292
 
3293
- #: src/features/login_protect.php:483
3294
  msgid ""
3295
  "This is a common problem and you may get locked out in the future if you "
3296
  "ignore this."
3297
  msgstr ""
3298
 
3299
- #: src/features/login_protect.php:484 src/processors/lockdown.php:219
3300
  #: src/processors/plugin_tracking.php:37
3301
  msgid "Learn More."
3302
  msgstr ""
3303
 
3304
- #: src/features/login_protect.php:539
 
 
 
 
3305
  msgid ""
3306
  "Login Guard blocks all automated and brute force attempts to log in to your "
3307
  "site."
3308
  msgstr ""
3309
 
3310
- #: src/features/login_protect.php:540 src/features/plugin.php:965
3311
  #: src/wizards/plugin.php:561 src/wizards/plugin.php:566
3312
  msgid "Login Guard"
3313
  msgstr ""
3314
 
3315
- #: src/features/login_protect.php:548
3316
  msgid "Adds Google reCAPTCHA to the Login Forms."
3317
  msgstr ""
3318
 
3319
- #: src/features/login_protect.php:555
3320
  msgid "Hide WordPress Login Page"
3321
  msgstr ""
3322
 
3323
- #: src/features/login_protect.php:556
3324
  #, php-format
3325
  msgid "Rename \"%s\""
3326
  msgstr ""
3327
 
3328
- #: src/features/login_protect.php:557
3329
  msgid "Hide Login Page"
3330
  msgstr ""
3331
 
3332
- #: src/features/login_protect.php:559
3333
  msgid ""
3334
  "To hide your wp-login.php page from brute force attacks and hacking attempts "
3335
  "- if your login page cannot be found, no-one can login."
3336
  msgstr ""
3337
 
3338
- #: src/features/login_protect.php:560
3339
  msgid ""
3340
  "This is not required for complete security and if your site has irregular or "
3341
  "inconsistent configuration it may not work for you."
3342
  msgstr ""
3343
 
3344
- #: src/features/login_protect.php:565 src/features/login_protect.php:646
3345
  #: src/features/user_management.php:344
3346
  msgid "Multi-Factor Authentication"
3347
  msgstr ""
3348
 
3349
- #: src/features/login_protect.php:566
3350
  msgid "Multi-Factor Auth"
3351
  msgstr ""
3352
 
3353
- #: src/features/login_protect.php:568 src/features/user_management.php:341
3354
  msgid ""
3355
  "Verifies the identity of users who log in to your site - i.e. they are who "
3356
  "they say they are."
3357
  msgstr ""
3358
 
3359
- #: src/features/login_protect.php:569 src/features/login_protect.php:579
3360
- #: src/features/login_protect.php:588 src/features/login_protect.php:606
3361
  msgid "You may combine multiple authentication factors for increased security."
3362
  msgstr ""
3363
 
3364
- #: src/features/login_protect.php:574
3365
  msgid "Email Two-Factor Authentication"
3366
  msgstr ""
3367
 
3368
- #: src/features/login_protect.php:575
3369
  msgid "2FA - Email"
3370
  msgstr ""
3371
 
3372
- #: src/features/login_protect.php:577
3373
  msgid ""
3374
  "Verifies the identity of users who log in to your site using email-based one-"
3375
  "time-passwords."
3376
  msgstr ""
3377
 
3378
- #: src/features/login_protect.php:578 src/features/user_management.php:342
3379
  msgid "However, if your host blocks email sending you may lock yourself out."
3380
  msgstr ""
3381
 
3382
- #: src/features/login_protect.php:584
3383
  msgid "Google Authenticator Two-Factor Authentication"
3384
  msgstr ""
3385
 
3386
- #: src/features/login_protect.php:585
3387
  msgid "2FA - Google Authenticator"
3388
  msgstr ""
3389
 
3390
- #: src/features/login_protect.php:587
3391
  msgid ""
3392
  "Verifies the identity of users who log in to your site using Google "
3393
  "Authenticator one-time-passwords."
3394
  msgstr ""
3395
 
3396
- #: src/features/login_protect.php:593
3397
  msgid "Brute Force Login Protection"
3398
  msgstr ""
3399
 
3400
- #: src/features/login_protect.php:594
3401
  msgid "reCAPTCHA & Bots"
3402
  msgstr ""
3403
 
3404
- #: src/features/login_protect.php:596
3405
  msgid ""
3406
  "Blocks brute force hacking attacks against your login and registration pages."
3407
  msgstr ""
3408
 
3409
- #: src/features/login_protect.php:602
3410
  msgid "Yubikey Two-Factor Authentication"
3411
  msgstr ""
3412
 
3413
- #: src/features/login_protect.php:603
3414
  msgid "2FA -Yubikey"
3415
  msgstr ""
3416
 
3417
- #: src/features/login_protect.php:605
3418
  msgid ""
3419
  "Verifies the identity of users who log in to your site using Yubikey one-"
3420
  "time-passwords."
3421
  msgstr ""
3422
 
3423
- #: src/features/login_protect.php:636
3424
  msgid "Hide WP Login Page"
3425
  msgstr ""
3426
 
3427
- #: src/features/login_protect.php:637
3428
  msgid "Hide The WordPress Login Page"
3429
  msgstr ""
3430
 
3431
- #: src/features/login_protect.php:638
3432
  msgid "Creating a path here will disable your wp-login.php"
3433
  msgstr ""
3434
 
3435
- #: src/features/login_protect.php:640
3436
  #, php-format
3437
  msgid "Only letters and numbers are permitted: %s"
3438
  msgstr ""
3439
 
3440
- #: src/features/login_protect.php:642
3441
  #, php-format
3442
  msgid "Your current login URL is: %s"
3443
  msgstr ""
3444
 
3445
- #: src/features/login_protect.php:647
3446
  msgid "Require All Active Authentication Factors"
3447
  msgstr ""
3448
 
3449
- #: src/features/login_protect.php:648
3450
  msgid ""
3451
  "When enabled, all multi-factor authentication methods will be applied to a "
3452
  "user login. Disable to require only one to login."
3453
  msgstr ""
3454
 
3455
- #: src/features/login_protect.php:652
3456
  msgid "Multi-Factor By-Pass"
3457
  msgstr ""
3458
 
3459
- #: src/features/login_protect.php:653
3460
  msgid ""
3461
  "A User Can By-Pass Multi-Factor Authentication (MFA) For The Set Number Of "
3462
  "Days"
3463
  msgstr ""
3464
 
3465
- #: src/features/login_protect.php:654
3466
  msgid ""
3467
  "Enter the number of days a user can by-pass future MFA after a successful "
3468
  "MFA-login. 0 to disable."
3469
  msgstr ""
3470
 
3471
- #: src/features/login_protect.php:658
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3472
  #: src/processors/loginprotect_googleauthenticator.php:41
3473
  #: src/processors/loginprotect_googleauthenticator.php:45
3474
  #: src/processors/loginprotect_googleauthenticator.php:47
3475
- #: src/processors/loginprotect_googleauthenticator.php:185
 
 
3476
  msgid "Google Authenticator"
3477
  msgstr ""
3478
 
3479
- #: src/features/login_protect.php:659
3480
  msgid "Allow Users To Use Google Authenticator"
3481
  msgstr ""
3482
 
3483
- #: src/features/login_protect.php:660
3484
  msgid ""
3485
  "When enabled, users will have the option to add Google Authenticator to "
3486
  "their WordPress user profile"
3487
  msgstr ""
3488
 
3489
- #: src/features/login_protect.php:664 src/features/login_protect.php:670
3490
- #: src/features/login_protect.php:673
3491
  #: src/processors/loginprotect_twofactorauth.php:201
3492
  #: src/processors/loginprotect_twofactorauth.php:202
3493
  msgid "Email Authentication"
3494
  msgstr ""
3495
 
3496
- #: src/features/login_protect.php:665
3497
  #, php-format
3498
  msgid "Two-Factor Login Authentication By %s"
3499
  msgstr ""
3500
 
3501
- #: src/features/login_protect.php:665 src/features/plugin.php:955
3502
  #: src/processors/user_management.php:209
3503
  msgid "Email"
3504
  msgstr ""
3505
 
3506
- #: src/features/login_protect.php:666
3507
  msgid ""
3508
  "All users will be required to verify their login by email-based two-factor "
3509
  "authentication."
3510
  msgstr ""
3511
 
3512
- #: src/features/login_protect.php:670
3513
  msgid "Enforce"
3514
  msgstr ""
3515
 
3516
- #: src/features/login_protect.php:671
3517
  msgid "All User Roles Subject To Email Authentication"
3518
  msgstr ""
3519
 
3520
- #: src/features/login_protect.php:672
3521
  msgid ""
3522
  "Enforces email-based authentication on all users with the selected roles."
3523
  msgstr ""
3524
 
3525
- #: src/features/login_protect.php:673
3526
  #, php-format
3527
  msgid "This setting only applies to %s."
3528
  msgstr ""
3529
 
3530
- #: src/features/login_protect.php:677
3531
  msgid "Google reCAPTCHA"
3532
  msgstr ""
3533
 
3534
- #: src/features/login_protect.php:678
3535
  msgid "Protect WordPress Account Access Requests With Google reCAPTCHA"
3536
  msgstr ""
3537
 
3538
- #: src/features/login_protect.php:679
3539
  msgid ""
3540
  "Use Google reCAPTCHA on the user account forms such as login, register, etc."
3541
  msgstr ""
3542
 
3543
- #: src/features/login_protect.php:680
3544
  #, php-format
3545
  msgid "Use of any theme other than \"%s\", requires a Pro license."
3546
  msgstr ""
3547
 
3548
- #: src/features/login_protect.php:680
3549
  msgid "Light Theme"
3550
  msgstr ""
3551
 
3552
- #: src/features/login_protect.php:681
3553
  msgid ""
3554
  "You'll need to setup your Google reCAPTCHA API Keys in 'General' settings."
3555
  msgstr ""
3556
 
3557
- #: src/features/login_protect.php:682
3558
  msgid ""
3559
  "Some forms are more dynamic than others so if you experience problems, "
3560
  "please use non-Invisible reCAPTCHA."
3561
  msgstr ""
3562
 
3563
- #: src/features/login_protect.php:692
3564
  msgid "Protection Locations"
3565
  msgstr ""
3566
 
3567
- #: src/features/login_protect.php:693
3568
  msgid "Which Forms Should Be Protected"
3569
  msgstr ""
3570
 
3571
- #: src/features/login_protect.php:694
3572
  msgid "Choose the forms for which bot protection measures will be deployed."
3573
  msgstr ""
3574
 
3575
- #: src/features/login_protect.php:695
3576
  #, php-format
3577
  msgid "Use with 3rd party systems such as %s, requires a Pro license."
3578
  msgstr ""
3579
 
3580
- #: src/features/login_protect.php:699
3581
  msgid "Bot Protection"
3582
  msgstr ""
3583
 
3584
- #: src/features/login_protect.php:700
3585
  msgid "Protect WP Login From Automated Login Attempts By Bots"
3586
  msgstr ""
3587
 
3588
- #: src/features/login_protect.php:701
3589
  msgid ""
3590
  "Adds a dynamically (Javascript) generated checkbox to the login form that "
3591
  "prevents bots using automated login techniques."
3592
  msgstr ""
3593
 
3594
- #: src/features/login_protect.php:702
3595
  msgid "ON"
3596
  msgstr ""
3597
 
3598
- #: src/features/login_protect.php:706
3599
  msgid "Cooldown Period"
3600
  msgstr ""
3601
 
3602
- #: src/features/login_protect.php:707
3603
  msgid "Limit account access requests to every X seconds"
3604
  msgstr ""
3605
 
3606
- #: src/features/login_protect.php:708
3607
  msgid ""
3608
  "WordPress will process only ONE account access attempt per number of seconds "
3609
  "specified."
3610
  msgstr ""
3611
 
3612
- #: src/features/login_protect.php:709
3613
  msgid "Zero (0) turns this off."
3614
  msgstr ""
3615
 
3616
- #: src/features/login_protect.php:715
3617
  msgid "User Registration"
3618
  msgstr ""
3619
 
3620
- #: src/features/login_protect.php:716
3621
  msgid "Apply Brute Force Protection To User Registration And Lost Passwords"
3622
  msgstr ""
3623
 
3624
- #: src/features/login_protect.php:717
3625
  msgid ""
3626
  "When enabled, settings in this section will also apply to new user "
3627
  "registration and users trying to reset passwords."
3628
  msgstr ""
3629
 
3630
- #: src/features/login_protect.php:721
3631
  msgid "Enable Yubikey Authentication"
3632
  msgstr ""
3633
 
3634
- #: src/features/login_protect.php:722
3635
  msgid "Turn On / Off Yubikey Authentication On This Site"
3636
  msgstr ""
3637
 
3638
- #: src/features/login_protect.php:723
3639
  msgid ""
3640
  "Combined with your Yubikey API details this will form the basis of your "
3641
  "Yubikey Authentication"
3642
  msgstr ""
3643
 
3644
- #: src/features/login_protect.php:727
3645
  msgid "Yubikey App ID"
3646
  msgstr ""
3647
 
3648
- #: src/features/login_protect.php:728
3649
  msgid "Your Unique Yubikey App ID"
3650
  msgstr ""
3651
 
3652
- #: src/features/login_protect.php:729
3653
  msgid ""
3654
  "Combined with your Yubikey API Key this will form the basis of your Yubikey "
3655
  "Authentication"
3656
  msgstr ""
3657
 
3658
- #: src/features/login_protect.php:730
3659
  msgid ""
3660
  "Please review the info link on how to obtain your own Yubikey App ID and API "
3661
  "Key."
3662
  msgstr ""
3663
 
3664
- #: src/features/login_protect.php:734
3665
  msgid "Yubikey API Key"
3666
  msgstr ""
3667
 
3668
- #: src/features/login_protect.php:735
3669
  msgid "Your Unique Yubikey App API Key"
3670
  msgstr ""
3671
 
3672
- #: src/features/login_protect.php:736
3673
  msgid ""
3674
  "Combined with your Yubikey App ID this will form the basis of your Yubikey "
3675
  "Authentication."
3676
  msgstr ""
3677
 
3678
- #: src/features/login_protect.php:737
3679
  msgid ""
3680
  "Please review the info link on how to get your own Yubikey App ID and API "
3681
  "Key."
3682
  msgstr ""
3683
 
3684
- #: src/features/login_protect.php:741
3685
  msgid "Yubikey Unique Keys"
3686
  msgstr ""
3687
 
3688
- #: src/features/login_protect.php:742
3689
  msgid ""
3690
  "This method for Yubikeys is no longer supported. Please see your user profile"
3691
  msgstr ""
3692
 
3693
- #: src/features/login_protect.php:743
3694
  msgid "Format"
3695
  msgstr ""
3696
 
3697
- #: src/features/login_protect.php:744
3698
  msgid "Provide Username<->Yubikey Pairs that are usable for this site."
3699
  msgstr ""
3700
 
3701
- #: src/features/login_protect.php:745
3702
  msgid ""
3703
  "If a Username if not assigned a Yubikey, Yubikey Authentication is OFF for "
3704
  "that user."
3705
  msgstr ""
3706
 
3707
- #: src/features/login_protect.php:746
3708
  msgid ""
3709
  "Each [Username,Key] pair should be separated by a new line: you only need to "
3710
  "provide the first 12 characters of the yubikey."
3711
  msgstr ""
3712
 
3713
- #: src/features/login_protect.php:750
3714
  msgid "GASP Checkbox Text"
3715
  msgstr ""
3716
 
3717
- #: src/features/login_protect.php:751
3718
  msgid "The User Message Displayed Next To The GASP Checkbox"
3719
  msgstr ""
3720
 
3721
- #: src/features/login_protect.php:752
3722
  msgid ""
3723
  "You can change the text displayed to the user beside the checkbox if you "
3724
  "need a custom message."
3725
  msgstr ""
3726
 
3727
- #: src/features/login_protect.php:757
3728
  msgid "GASP Alert Text"
3729
  msgstr ""
3730
 
3731
- #: src/features/login_protect.php:758
3732
  msgid "The Message Displayed If The User Doesn't Check The Box"
3733
  msgstr ""
3734
 
3735
- #: src/features/login_protect.php:759
3736
  msgid ""
3737
  "You can change the text displayed to the user in the alert message if they "
3738
  "don't check the box."
@@ -4159,7 +4197,7 @@ msgstr ""
4159
  msgid "Cookie"
4160
  msgstr ""
4161
 
4162
- #: src/features/plugin.php:938 src/features/traffic.php:381
4163
  msgid "IP"
4164
  msgstr ""
4165
 
@@ -4268,7 +4306,7 @@ msgid "Premium Plugin Support Centre"
4268
  msgstr ""
4269
 
4270
  #: src/features/plugin.php:974 src/features/sessions.php:54
4271
- #: src/features/traffic.php:463 src/features/user_management.php:314
4272
  msgid "User Management"
4273
  msgstr ""
4274
 
@@ -4322,144 +4360,166 @@ msgstr ""
4322
  msgid "Sharing"
4323
  msgstr ""
4324
 
4325
- #: src/features/traffic.php:66
4326
  #, php-format
4327
  msgid "%s is a Pro-only feature."
4328
  msgstr ""
4329
 
4330
- #: src/features/traffic.php:66
4331
  msgid "Traffic Watch"
4332
  msgstr ""
4333
 
4334
- #: src/features/traffic.php:71
4335
  msgid ""
4336
  "Traffic Watcher will not run because visitor IP address detection is not "
4337
  "correctly configured."
4338
  msgstr ""
4339
 
4340
- #: src/features/traffic.php:184
4341
  msgid "Traffic Watch Viewer"
4342
  msgstr ""
4343
 
4344
- #: src/features/traffic.php:360
4345
  msgid "unknown"
4346
  msgstr ""
4347
 
4348
- #: src/features/traffic.php:368 src/processors/firewall.php:271
4349
  msgid "Unknown"
4350
  msgstr ""
4351
 
4352
- #: src/features/traffic.php:382
4353
  msgid "Logged-In"
4354
  msgstr ""
4355
 
4356
- #: src/features/traffic.php:383
4357
  msgid "Location"
4358
  msgstr ""
4359
 
4360
- #: src/features/traffic.php:384
4361
  msgid "User Agent"
4362
  msgstr ""
4363
 
4364
- #: src/features/traffic.php:389
4365
  msgid "Response"
4366
  msgstr ""
4367
 
4368
- #: src/features/traffic.php:390
4369
  msgid "Transgression"
4370
  msgstr ""
4371
 
4372
- #: src/features/traffic.php:434
4373
  msgid "Traffic Watch Log"
4374
  msgstr ""
4375
 
4376
- #: src/features/traffic.php:435
4377
  msgid "Review Site Traffic Logs "
4378
  msgstr ""
4379
 
4380
- #: src/features/traffic.php:453
4381
  msgid "Monitor and review all requests to your site."
4382
  msgstr ""
4383
 
4384
- #: src/features/traffic.php:454
4385
  msgid ""
4386
  "Required only if you need to review and investigate and monitor requests to "
4387
  "your site"
4388
  msgstr ""
4389
 
4390
- #: src/features/traffic.php:460
4391
  msgid "Traffic Watch Options"
4392
  msgstr ""
4393
 
4394
- #: src/features/traffic.php:462
4395
  msgid "Provides finer control over the Traffic Watch system."
4396
  msgstr ""
4397
 
4398
- #: src/features/traffic.php:465
4399
  msgid "Traffic Logging Options"
4400
  msgstr ""
4401
 
4402
- #: src/features/traffic.php:494
4403
  msgid "Traffic Log Exclusions"
4404
  msgstr ""
4405
 
4406
- #: src/features/traffic.php:495
4407
  msgid "Select Which Types Of Requests To Exclude"
4408
  msgstr ""
4409
 
4410
- #: src/features/traffic.php:496
4411
  msgid ""
4412
  "Select request types that you don't want to appear in the traffic viewer."
4413
  msgstr ""
4414
 
4415
- #: src/features/traffic.php:497
4416
  msgid ""
4417
  "If a request matches any exclusion rule, it will not show on the traffic "
4418
  "viewer."
4419
  msgstr ""
4420
 
4421
- #: src/features/traffic.php:501
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4422
  msgid "Auto Expiry Cleaning"
4423
  msgstr ""
4424
 
4425
- #: src/features/traffic.php:502
4426
  msgid "Enable Traffic Log Auto Expiry"
4427
  msgstr ""
4428
 
4429
- #: src/features/traffic.php:503
4430
  msgid "DB cleanup will delete logs older than this maximum value (in days)."
4431
  msgstr ""
4432
 
4433
- #: src/features/traffic.php:507
4434
  msgid "Max Log Length"
4435
  msgstr ""
4436
 
4437
- #: src/features/traffic.php:508
4438
  msgid "Maximum Traffic Log Length To Keep"
4439
  msgstr ""
4440
 
4441
- #: src/features/traffic.php:509
4442
  msgid "DB cleanup will delete logs to maintain this maximum number of records."
4443
  msgstr ""
4444
 
4445
- #: src/features/traffic.php:513
4446
  msgid "Auto Disable"
4447
  msgstr ""
4448
 
4449
- #: src/features/traffic.php:514
4450
  msgid "Auto Disable Traffic Logging After 1 Week"
4451
  msgstr ""
4452
 
4453
- #: src/features/traffic.php:517
4454
  #, php-format
4455
  msgid "Auto Disable At: %s"
4456
  msgstr ""
4457
 
4458
- #: src/features/traffic.php:522
4459
  msgid "Turn on to prevent unnecessary long-term traffic logging."
4460
  msgstr ""
4461
 
4462
- #: src/features/traffic.php:523
4463
  msgid "Timer resets after options save."
4464
  msgstr ""
4465
 
@@ -5006,6 +5066,7 @@ msgid "Thank you."
5006
  msgstr ""
5007
 
5008
  #: src/processors/autoupdates.php:540
 
5009
  #, php-format
5010
  msgid "Notice: %s"
5011
  msgstr ""
@@ -5110,7 +5171,6 @@ msgid "Head over to: %s"
5110
  msgstr ""
5111
 
5112
  #: src/processors/base_wpsf.php:99 src/processors/base_wpsf.php:107
5113
- #: src/processors/loginprotect_googleauthenticator.php:223
5114
  msgid "Whoops."
5115
  msgstr ""
5116
 
@@ -5200,7 +5260,7 @@ msgstr ""
5200
  msgid "Firewall Trigger: %s."
5201
  msgstr ""
5202
 
5203
- #: src/processors/firewall.php:160 src/processors/firewall.php:539
5204
  msgid "EXE File Uploads"
5205
  msgstr ""
5206
 
@@ -5248,37 +5308,37 @@ msgstr ""
5248
  msgid "Firewall Block Response: %s."
5249
  msgstr ""
5250
 
5251
- #: src/processors/firewall.php:466
5252
  #, php-format
5253
  msgid "%s has blocked a page visit to your site."
5254
  msgstr ""
5255
 
5256
- #: src/processors/firewall.php:467
5257
  msgid "Log details for this visitor are below:"
5258
  msgstr ""
5259
 
5260
- #: src/processors/firewall.php:472
5261
  #, php-format
5262
  msgid "You can look up the offending IP Address here: %s"
5263
  msgstr ""
5264
 
5265
- #: src/processors/firewall.php:473
5266
  msgid "Firewall Block Alert"
5267
  msgstr ""
5268
 
5269
- #: src/processors/firewall.php:527
5270
  msgid "Directory Traversal"
5271
  msgstr ""
5272
 
5273
- #: src/processors/firewall.php:542
5274
  msgid "Leading Schema"
5275
  msgstr ""
5276
 
5277
- #: src/processors/firewall.php:548
5278
  msgid "Aggressive Rules"
5279
  msgstr ""
5280
 
5281
- #: src/processors/firewall.php:551
5282
  msgid "Unknown Rules"
5283
  msgstr ""
5284
 
@@ -5311,7 +5371,7 @@ msgstr ""
5311
 
5312
  #: src/processors/hackprotect_corechecksumscan.php:265
5313
  #: src/processors/hackprotect_filecleanerscan.php:254
5314
- #: src/processors/hackprotect_ptguard.php:460
5315
  #: src/processors/user_management.php:207
5316
  #: src/processors/user_management.php:235
5317
  msgid "Site URL"
@@ -5470,52 +5530,66 @@ msgstr ""
5470
  msgid "Vulnerable Versions"
5471
  msgstr ""
5472
 
5473
- #: src/processors/hackprotect_ptguard.php:414
 
 
 
 
 
 
 
 
 
 
5474
  msgid "Silenced repeated email alert from Plugin/Theme Scan Guard"
5475
  msgstr ""
5476
 
5477
- #: src/processors/hackprotect_ptguard.php:456
5478
  #, php-format
5479
  msgid ""
5480
  "%s has detected at least 1 Plugins/Themes have been modified on your site."
5481
  msgstr ""
5482
 
5483
- #: src/processors/hackprotect_ptguard.php:458
5484
  msgid ""
5485
  "You will receive only 1 email notification about these changes in a 1 week "
5486
  "period."
5487
  msgstr ""
5488
 
5489
- #: src/processors/hackprotect_ptguard.php:462
5490
  msgid "Details of the problem items are below:"
5491
  msgstr ""
5492
 
5493
- #: src/processors/hackprotect_ptguard.php:467
5494
  msgid "Modified Plugins:"
5495
  msgstr ""
5496
 
5497
- #: src/processors/hackprotect_ptguard.php:475
5498
  msgid "Modified Themes:"
5499
  msgstr ""
5500
 
5501
- #: src/processors/hackprotect_ptguard.php:485
5502
  msgid "Run the scanner"
5503
  msgstr ""
5504
 
5505
- #: src/processors/hackprotect_ptguard.php:491
5506
  msgid "Plugins/Themes Have Been Altered"
5507
  msgstr ""
5508
 
5509
- #: src/processors/hackprotect_ptguard.php:496
5510
  #, php-format
5511
  msgid "Successfully sent Plugin/Theme Guard email alert to: %s"
5512
  msgstr ""
5513
 
5514
- #: src/processors/hackprotect_ptguard.php:499
5515
  #, php-format
5516
  msgid "Failed to send Plugin/Theme Guard email alert to: %s"
5517
  msgstr ""
5518
 
 
 
 
 
5519
  #: src/processors/hackprotect_wpvulnscan.php:112
5520
  msgid "Vulnerable"
5521
  msgstr ""
@@ -5662,102 +5736,90 @@ msgstr ""
5662
  msgid "To turn this notice off, disable 2-Factor Authentication."
5663
  msgstr ""
5664
 
5665
- #: src/processors/loginprotect_cooldown.php:24
5666
- msgid "Request Cooldown in effect."
5667
  msgstr ""
5668
 
5669
- #: src/processors/loginprotect_cooldown.php:26
5670
- #, php-format
5671
- msgid "You must wait %s seconds before attempting this action again."
5672
  msgstr ""
5673
 
5674
- #: src/processors/loginprotect_cooldown.php:31
5675
  msgid ""
5676
- "Cooldown triggered and request (login/register/lost-password) was blocked."
 
5677
  msgstr ""
5678
 
5679
- #: src/processors/loginprotect_gasp.php:29
5680
- msgid "You MUST enable Javascript to be able to login"
5681
- msgstr ""
5682
-
5683
- #: src/processors/loginprotect_gasp.php:60
5684
- #: src/processors/loginprotect_gasp.php:104
5685
- #, php-format
5686
- msgid "User \"%s\" attempted to %s but GASP checkbox was not present."
5687
- msgstr ""
5688
-
5689
- #: src/processors/loginprotect_gasp.php:62
5690
- #: src/processors/loginprotect_gasp.php:71
5691
- #: src/processors/loginprotect_gasp.php:106
5692
- #: src/processors/loginprotect_gasp.php:115
5693
- msgid "Probably a BOT."
5694
- msgstr ""
5695
-
5696
- #: src/processors/loginprotect_gasp.php:65
5697
- #: src/processors/loginprotect_gasp.php:109
5698
- msgid "You must check that box to say you're not a bot."
5699
  msgstr ""
5700
 
5701
- #: src/processors/loginprotect_gasp.php:69
5702
- #: src/processors/loginprotect_gasp.php:113
5703
- #, php-format
5704
- msgid "User \"%s\" attempted to %s but they were caught by the GASP honeypot."
5705
  msgstr ""
5706
 
5707
- #: src/processors/loginprotect_gasp.php:74
5708
- #: src/processors/loginprotect_gasp.php:118
5709
- #, php-format
5710
- msgid "You appear to be a bot - terminating %s attempt."
5711
  msgstr ""
5712
 
5713
- #: src/processors/loginprotect_googleauthenticator.php:36
5714
- msgid "Provide the current code generated by your Google Authenticator app."
5715
- msgstr ""
5716
-
5717
- #: src/processors/loginprotect_googleauthenticator.php:37
5718
- msgid "To reset this QR Code enter fake data here."
5719
  msgstr ""
5720
 
 
5721
  #: src/processors/loginprotect_googleauthenticator.php:38
5722
  msgid ""
5723
  "Use your Google Authenticator app to scan this QR code and enter the one "
5724
  "time password below."
5725
  msgstr ""
5726
 
 
5727
  #: src/processors/loginprotect_googleauthenticator.php:39
5728
  msgid ""
5729
  "If you have a problem with scanning the QR code enter this code manually "
5730
  "into the app."
5731
  msgstr ""
5732
 
 
5733
  #: src/processors/loginprotect_googleauthenticator.php:40
5734
  msgid "Check the box to remove Google Authenticator login authentication."
5735
  msgstr ""
5736
 
 
5737
  #: src/processors/loginprotect_googleauthenticator.php:41
5738
  #, php-format
5739
  msgid "Remove %s"
5740
  msgstr ""
5741
 
5742
- #: src/processors/loginprotect_googleauthenticator.php:42
5743
- #: src/processors/loginprotect_googleauthenticator.php:259
5744
- msgid "Google Authenticator Code"
5745
  msgstr ""
5746
 
 
5747
  #: src/processors/loginprotect_googleauthenticator.php:43
5748
  msgid "Manual Code"
5749
  msgstr ""
5750
 
 
5751
  #: src/processors/loginprotect_googleauthenticator.php:44
5752
  msgid "Scan This QR Code"
5753
  msgstr ""
5754
 
 
 
 
 
 
5755
  #: src/processors/loginprotect_googleauthenticator.php:46
5756
  #: src/processors/loginprotect_yubikey.php:46
5757
  #, php-format
5758
  msgid "Sorry, %s may not be added to another user's account."
5759
  msgstr ""
5760
 
 
5761
  #: src/processors/loginprotect_googleauthenticator.php:47
5762
  #: src/processors/loginprotect_yubikey.php:47
5763
  #, php-format
@@ -5766,6 +5828,11 @@ msgid ""
5766
  "Administrator."
5767
  msgstr ""
5768
 
 
 
 
 
 
5769
  #: src/processors/loginprotect_googleauthenticator.php:48
5770
  #: src/processors/loginprotect_twofactorauth.php:204
5771
  #: src/processors/loginprotect_yubikey.php:48
@@ -5773,13 +5840,138 @@ msgstr ""
5773
  msgid "Provided by %s"
5774
  msgstr ""
5775
 
 
5776
  #: src/processors/loginprotect_googleauthenticator.php:49
5777
  #: src/processors/loginprotect_yubikey.php:49
5778
  msgid "Understand how to remove Google Authenticator"
5779
  msgstr ""
5780
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5781
  #: src/processors/loginprotect_googleauthenticator.php:107
5782
- #: src/processors/loginprotect_googleauthenticator.php:153
5783
  msgid "Google Authenticator was successfully removed from the account."
5784
  msgstr ""
5785
 
@@ -5789,140 +5981,118 @@ msgid ""
5789
  "code is correct."
5790
  msgstr ""
5791
 
5792
- #: src/processors/loginprotect_googleauthenticator.php:145
5793
  #: src/processors/loginprotect_yubikey.php:80
5794
  msgid "One Time Password (OTP) was not valid."
5795
  msgstr ""
5796
 
5797
- #: src/processors/loginprotect_googleauthenticator.php:145
5798
  #: src/processors/loginprotect_yubikey.php:80
5799
  msgid "Please try again."
5800
  msgstr ""
5801
 
5802
- #: src/processors/loginprotect_googleauthenticator.php:158
5803
  msgid ""
5804
  "An email has been sent to you in order to confirm Google Authenticator "
5805
  "removal"
5806
  msgstr ""
5807
 
5808
- #: src/processors/loginprotect_googleauthenticator.php:162
5809
  msgid ""
5810
  "We tried to send an email for you to confirm Google Authenticator removal "
5811
  "but it failed."
5812
  msgstr ""
5813
 
5814
- #: src/processors/loginprotect_googleauthenticator.php:184
5815
  #, php-format
5816
  msgid "%s was successfully added to your account."
5817
  msgstr ""
5818
 
5819
- #: src/processors/loginprotect_googleauthenticator.php:223
5820
- msgid "Did we forget to use the Google Authenticator?"
5821
- msgstr ""
5822
-
5823
- #: src/processors/loginprotect_googleauthenticator.php:230
5824
- msgid "Oh dear."
5825
- msgstr ""
5826
-
5827
- #: src/processors/loginprotect_googleauthenticator.php:230
5828
- msgid "Google Authenticator Code Failed."
5829
- msgstr ""
5830
-
5831
- #: src/processors/loginprotect_googleauthenticator.php:258
5832
  msgid "Please use your Google Authenticator App to retrieve your code."
5833
  msgstr ""
5834
 
5835
- #: src/processors/loginprotect_googleauthenticator.php:277
5836
  msgid ""
5837
  "You have requested the removal of Google Authenticator from your WordPress "
5838
  "account."
5839
  msgstr ""
5840
 
5841
- #: src/processors/loginprotect_googleauthenticator.php:278
5842
  msgid "Please click the link below to confirm."
5843
  msgstr ""
5844
 
5845
- #: src/processors/loginprotect_googleauthenticator.php:283
5846
  msgid "Google Authenticator Removal Confirmation"
5847
  msgstr ""
5848
 
5849
- #: src/processors/loginprotect_googleauthenticator.php:307
5850
  msgid "Google Authenticator was successfully removed from this account."
5851
  msgstr ""
5852
 
5853
- #: src/processors/loginprotect_googleauthenticator.php:342
5854
- #, php-format
5855
- msgid ""
5856
- "User \"%s\" verified their identity using Google Authenticator Two-Factor "
5857
- "Authentication."
5858
- msgstr ""
5859
-
5860
- #: src/processors/loginprotect_googleauthenticator.php:350
5861
- #, php-format
5862
- msgid ""
5863
- "User \"%s\" failed to verify their identity using Google Authenticator Two-"
5864
- "Factor Authentication."
5865
- msgstr ""
5866
-
5867
- #: src/processors/loginprotect_intent.php:118
5868
  msgid "Success"
5869
  msgstr ""
5870
 
5871
- #: src/processors/loginprotect_intent.php:118
5872
  msgid "Thank you for authenticating your login."
5873
  msgstr ""
5874
 
5875
- #: src/processors/loginprotect_intent.php:122
 
 
 
 
5876
  msgid "One or more of your authentication codes failed or was missing"
5877
  msgstr ""
5878
 
5879
- #: src/processors/loginprotect_intent.php:260
5880
  msgid "Please supply all authentication codes"
5881
  msgstr ""
5882
 
5883
- #: src/processors/loginprotect_intent.php:263
5884
  msgid "Please supply at least 1 authentication code"
5885
  msgstr ""
5886
 
5887
- #: src/processors/loginprotect_intent.php:276
5888
  msgid "Cancel Login"
5889
  msgstr ""
5890
 
5891
- #: src/processors/loginprotect_intent.php:277
5892
  msgid "Time Remaining"
5893
  msgstr ""
5894
 
5895
- #: src/processors/loginprotect_intent.php:278
5896
  msgid "Calculating"
5897
  msgstr ""
5898
 
5899
- #: src/processors/loginprotect_intent.php:279
5900
  msgid "Seconds"
5901
  msgstr ""
5902
 
5903
- #: src/processors/loginprotect_intent.php:280
5904
  msgid "Login Expired"
5905
  msgstr ""
5906
 
5907
- #: src/processors/loginprotect_intent.php:281
5908
  msgid "Verify My Login"
5909
  msgstr ""
5910
 
5911
- #: src/processors/loginprotect_intent.php:283
5912
  msgid "What is this?"
5913
  msgstr ""
5914
 
5915
- #: src/processors/loginprotect_intent.php:285
5916
  #, php-format
5917
  msgid "%s Login Verification"
5918
  msgstr ""
5919
 
5920
- #: src/processors/loginprotect_intent.php:287
5921
  #, php-format
5922
  msgid "Don't ask again on this browser for %s."
5923
  msgstr ""
5924
 
5925
- #: src/processors/loginprotect_intent.php:288
5926
  #, php-format
5927
  msgid "%s day"
5928
  msgid_plural "%s days"
@@ -5930,16 +6100,8 @@ msgstr[0] ""
5930
  msgstr[1] ""
5931
 
5932
  #: src/processors/loginprotect_twofactorauth.php:42
5933
- #, php-format
5934
- msgid ""
5935
- "User \"%s\" verified their identity using Email Two-Factor Authentication."
5936
- msgstr ""
5937
-
5938
  #: src/processors/loginprotect_twofactorauth.php:50
5939
- #, php-format
5940
- msgid ""
5941
- "User \"%s\" failed to verify their identity using Email Two-Factor "
5942
- "Authentication."
5943
  msgstr ""
5944
 
5945
  #: src/processors/loginprotect_twofactorauth.php:80
@@ -5963,14 +6125,6 @@ msgstr ""
5963
  msgid "Verification Code: %s"
5964
  msgstr ""
5965
 
5966
- #: src/processors/loginprotect_twofactorauth.php:159
5967
- msgid "Login Details"
5968
- msgstr ""
5969
-
5970
- #: src/processors/loginprotect_twofactorauth.php:160
5971
- msgid "URL"
5972
- msgstr ""
5973
-
5974
  #: src/processors/loginprotect_twofactorauth.php:167
5975
  msgid "Why no login link?"
5976
  msgstr ""
@@ -6066,7 +6220,9 @@ msgid "Yubikey ID"
6066
  msgstr ""
6067
 
6068
  #: src/processors/loginprotect_yubikey.php:44
6069
- #: src/processors/loginprotect_yubikey.php:264
 
 
6070
  msgid "Yubikey OTP"
6071
  msgstr ""
6072
 
@@ -6097,57 +6253,50 @@ msgstr ""
6097
  msgid "No changes were made to your Yubikey configuration"
6098
  msgstr ""
6099
 
6100
- #: src/processors/loginprotect_yubikey.php:239
6101
- #: src/processors/loginprotect_yubikey.php:359
6102
- #, php-format
6103
- msgid ""
6104
- "User \"%s\" successfully logged in using a validated Yubikey One Time "
6105
- "Password."
6106
- msgstr ""
6107
-
6108
- #: src/processors/loginprotect_yubikey.php:246
6109
- #, php-format
6110
- msgid ""
6111
- "User \"%s\" failed to verify their identity using Yubikey One Time Password."
6112
- msgstr ""
6113
-
6114
- #: src/processors/loginprotect_yubikey.php:262
6115
  msgid "Use your Yubikey to generate a new code."
6116
  msgstr ""
6117
 
6118
- #: src/processors/loginprotect_yubikey.php:339
6119
  #, php-format
6120
  msgid ""
6121
  "User \"%s\" logged in without a Yubikey One Time Password because no "
6122
  "username-yubikey pair was found for this user."
6123
  msgstr ""
6124
 
6125
- #: src/processors/loginprotect_yubikey.php:346
6126
  #, php-format
6127
  msgid ""
6128
  "User \"%s\" attempted to login but Yubikey ID \"%s\" used was not in list of "
6129
  "authorised keys."
6130
  msgstr ""
6131
 
6132
- #: src/processors/loginprotect_yubikey.php:352
6133
- #: src/processors/loginprotect_yubikey.php:370
6134
  #, php-format
6135
  msgid "ERROR: %s"
6136
  msgstr ""
6137
 
6138
- #: src/processors/loginprotect_yubikey.php:352
6139
  msgid ""
6140
  "The Yubikey provided is not on the list of permitted keys for this user."
6141
  msgstr ""
6142
 
6143
- #: src/processors/loginprotect_yubikey.php:365
 
 
 
 
 
 
 
6144
  #, php-format
6145
  msgid ""
6146
  "User \"%s\" attempted to login but Yubikey One Time Password failed to "
6147
  "validate due to invalid Yubi API response.\"."
6148
  msgstr ""
6149
 
6150
- #: src/processors/loginprotect_yubikey.php:370
6151
  msgid "The Yubikey authentication was not validated successfully."
6152
  msgstr ""
6153
 
@@ -6495,24 +6644,34 @@ msgstr ""
6495
  msgid "Invalid email address"
6496
  msgstr ""
6497
 
6498
- #: src/wizards/login_protect.php:117
 
 
 
 
 
 
 
 
 
 
6499
  msgid "Code was empty."
6500
  msgstr ""
6501
 
6502
- #: src/wizards/login_protect.php:144
6503
  msgid "Google Authenticator was enabled for the site."
6504
  msgstr ""
6505
 
6506
- #: src/wizards/login_protect.php:159
6507
  #, php-format
6508
  msgid "Multi-Factor Authentication was %s for the site."
6509
  msgstr ""
6510
 
6511
- #: src/wizards/login_protect.php:160
6512
  msgid "enabled"
6513
  msgstr ""
6514
 
6515
- #: src/wizards/login_protect.php:160
6516
  msgid "disabled"
6517
  msgstr ""
6518
 
1
  msgid ""
2
  msgstr ""
3
  "Project-Id-Version: WPSF v2.0\n"
4
+ "POT-Creation-Date: 2018-09-19 17:21+0100\n"
5
+ "PO-Revision-Date: 2018-09-19 17:21+0100\n"
6
  "Last-Translator: \n"
7
  "Language-Team: \n"
8
  "Language: en_GB\n"
51
  msgid "Enter your Security Admin Access Key"
52
  msgstr ""
53
 
54
+ #: src/features/admin_access_restriction.php:266
55
  msgid "Security Admin key accepted."
56
  msgstr ""
57
 
58
+ #: src/features/admin_access_restriction.php:269
59
  msgid "Security Admin key not accepted."
60
  msgstr ""
61
 
62
+ #: src/features/admin_access_restriction.php:439
63
  msgid "Security Admin Protection"
64
  msgstr ""
65
 
66
+ #: src/features/admin_access_restriction.php:448
67
  msgid "The Security Admin protection is not active."
68
  msgstr ""
69
 
70
+ #: src/features/admin_access_restriction.php:452
71
  #: src/features/audit_trail.php:304 src/features/base_wpsf.php:169
72
  #: src/features/base_wpsf.php:209 src/features/hack_protect.php:656
73
  #: src/features/hack_protect.php:677 src/features/hack_protect.php:698
76
  msgid "Options"
77
  msgstr ""
78
 
79
+ #: src/features/admin_access_restriction.php:453
80
  msgid "Security Admin should be turned-on to protect your security settings."
81
  msgstr ""
82
 
83
+ #: src/features/admin_access_restriction.php:483
84
  #: src/features/audit_trail.php:290 src/features/autoupdates.php:186
85
  #: src/features/comments_filter.php:103 src/features/firewall.php:59
86
  #: src/features/hack_protect.php:759 src/features/headers.php:120
87
  #: src/features/ips.php:302 src/features/lockdown.php:85
88
+ #: src/features/login_protect.php:604 src/features/sessions.php:51
89
  #: src/features/statistics.php:51 src/features/statistics.php:60
90
+ #: src/features/traffic.php:465 src/features/user_management.php:311
91
  #, php-format
92
  msgid "Enable Module: %s"
93
  msgstr ""
94
 
95
+ #: src/features/admin_access_restriction.php:485
96
+ #: src/features/admin_access_restriction.php:495
97
+ #: src/features/admin_access_restriction.php:504
98
+ #: src/features/admin_access_restriction.php:514
99
  #: src/features/audit_trail.php:292 src/features/audit_trail.php:301
100
  #: src/features/audit_trail.php:310 src/features/autoupdates.php:188
101
  #: src/features/autoupdates.php:197 src/features/autoupdates.php:206
102
  #: src/features/autoupdates.php:216 src/features/autoupdates.php:226
103
+ #: src/features/base_wpsf.php:322 src/features/comments_filter.php:105
104
  #: src/features/comments_filter.php:114 src/features/comments_filter.php:124
105
  #: src/features/comments_filter.php:133 src/features/firewall.php:61
106
  #: src/features/hack_protect.php:754 src/features/hack_protect.php:761
110
  #: src/features/headers.php:122 src/features/headers.php:131
111
  #: src/features/headers.php:140 src/features/ips.php:304
112
  #: src/features/ips.php:314 src/features/ips.php:324
113
+ #: src/features/license.php:691 src/features/lockdown.php:87
114
  #: src/features/lockdown.php:96 src/features/lockdown.php:105
115
+ #: src/features/lockdown.php:114 src/features/login_protect.php:607
116
+ #: src/features/login_protect.php:616 src/features/login_protect.php:627
117
+ #: src/features/login_protect.php:636 src/features/login_protect.php:645
118
+ #: src/features/login_protect.php:655 src/features/login_protect.php:664
119
+ #: src/features/login_protect.php:673 src/features/plugin.php:733
120
  #: src/features/plugin.php:740 src/features/plugin.php:755
121
  #: src/features/sessions.php:53 src/features/statistics.php:53
122
  #: src/features/statistics.php:62 src/features/statistics.php:71
123
+ #: src/features/traffic.php:467 src/features/traffic.php:476
124
  #: src/features/user_management.php:313 src/features/user_management.php:323
125
  #: src/features/user_management.php:332 src/features/user_management.php:341
126
  #: src/features/user_management.php:350
127
  msgid "Purpose"
128
  msgstr ""
129
 
130
+ #: src/features/admin_access_restriction.php:485
131
+ #: src/features/admin_access_restriction.php:495
132
  msgid ""
133
  "Restricts access to this plugin preventing unauthorized changes to your "
134
  "security settings."
135
  msgstr ""
136
 
137
+ #: src/features/admin_access_restriction.php:486
138
+ #: src/features/admin_access_restriction.php:496
139
+ #: src/features/admin_access_restriction.php:505
140
  #: src/features/audit_trail.php:293 src/features/audit_trail.php:302
141
  #: src/features/audit_trail.php:311 src/features/autoupdates.php:189
142
  #: src/features/autoupdates.php:198 src/features/autoupdates.php:208
143
+ #: src/features/autoupdates.php:217 src/features/base_wpsf.php:323
144
  #: src/features/comments_filter.php:106 src/features/comments_filter.php:115
145
  #: src/features/comments_filter.php:125 src/features/comments_filter.php:134
146
  #: src/features/firewall.php:62 src/features/firewall.php:71
151
  #: src/features/hack_protect.php:819 src/features/headers.php:123
152
  #: src/features/headers.php:132 src/features/headers.php:141
153
  #: src/features/ips.php:305 src/features/ips.php:315 src/features/ips.php:325
154
+ #: src/features/license.php:692 src/features/lockdown.php:88
155
  #: src/features/lockdown.php:97 src/features/lockdown.php:106
156
+ #: src/features/lockdown.php:115 src/features/login_protect.php:608
157
+ #: src/features/login_protect.php:617 src/features/login_protect.php:628
158
+ #: src/features/login_protect.php:646 src/features/login_protect.php:665
159
+ #: src/features/login_protect.php:776 src/features/plugin.php:757
160
  #: src/features/sessions.php:54 src/features/statistics.php:54
161
  #: src/features/statistics.php:63 src/features/statistics.php:72
162
+ #: src/features/traffic.php:468 src/features/traffic.php:477
163
  #: src/features/user_management.php:314 src/features/user_management.php:324
164
  #: src/features/user_management.php:333 src/features/user_management.php:342
165
  #: src/features/user_management.php:351
166
  msgid "Recommendation"
167
  msgstr ""
168
 
169
+ #: src/features/admin_access_restriction.php:486
170
  #: src/features/audit_trail.php:293 src/features/autoupdates.php:189
171
  #: src/features/comments_filter.php:106 src/features/firewall.php:62
172
  #: src/features/hack_protect.php:762 src/features/hack_protect.php:771
173
  #: src/features/hack_protect.php:781 src/features/hack_protect.php:790
174
  #: src/features/hack_protect.php:799 src/features/ips.php:305
175
  #: src/features/ips.php:315 src/features/lockdown.php:88
176
+ #: src/features/login_protect.php:608 src/features/sessions.php:54
177
  #: src/features/statistics.php:54 src/features/statistics.php:63
178
  #: src/features/user_management.php:314
179
  #, php-format
180
  msgid "Keep the %s feature turned on."
181
  msgstr ""
182
 
183
+ #: src/features/admin_access_restriction.php:486
184
+ #: src/features/admin_access_restriction.php:548 src/features/plugin.php:945
185
  #: src/features/plugin.php:947 src/wizards/base_wpsf.php:65
186
  msgid "Security Admin"
187
  msgstr ""
188
 
189
+ #: src/features/admin_access_restriction.php:487
190
  msgid "You need to also enter a new Access Key to enable this feature."
191
  msgstr ""
192
 
193
+ #: src/features/admin_access_restriction.php:489
194
  #: src/features/audit_trail.php:295 src/features/autoupdates.php:191
195
  #: src/features/comments_filter.php:108 src/features/firewall.php:64
196
  #: src/features/hack_protect.php:764 src/features/headers.php:125
197
  #: src/features/ips.php:308 src/features/lockdown.php:90
198
+ #: src/features/login_protect.php:605 src/features/sessions.php:56
199
  #: src/features/statistics.php:56 src/features/statistics.php:65
200
+ #: src/features/traffic.php:470 src/features/user_management.php:316
201
  #, php-format
202
  msgid "%s/%s Module"
203
  msgstr ""
204
 
205
+ #: src/features/admin_access_restriction.php:489
206
+ #: src/features/admin_access_restriction.php:619
207
  #: src/features/audit_trail.php:295 src/features/autoupdates.php:191
208
  #: src/features/comments_filter.php:108 src/features/firewall.php:64
209
  #: src/features/hack_protect.php:764 src/features/headers.php:125
210
  #: src/features/ips.php:308 src/features/lockdown.php:90
211
+ #: src/features/login_protect.php:605 src/features/sessions.php:56
212
  #: src/features/statistics.php:56 src/features/statistics.php:65
213
+ #: src/features/traffic.php:470 src/features/user_management.php:316
214
  msgid "Enable"
215
  msgstr ""
216
 
217
+ #: src/features/admin_access_restriction.php:489
218
  #: src/features/audit_trail.php:295 src/features/autoupdates.php:191
219
  #: src/features/comments_filter.php:108 src/features/firewall.php:64
220
  #: src/features/hack_protect.php:764 src/features/headers.php:125
221
  #: src/features/ips.php:308 src/features/lockdown.php:90
222
+ #: src/features/login_protect.php:605 src/features/sessions.php:56
223
  #: src/features/statistics.php:56 src/features/statistics.php:65
224
+ #: src/features/traffic.php:470 src/features/user_management.php:316
225
  msgid "Disable"
226
  msgstr ""
227
 
228
+ #: src/features/admin_access_restriction.php:493
229
  msgid "Security Admin Restriction Settings"
230
  msgstr ""
231
 
232
+ #: src/features/admin_access_restriction.php:496
233
+ #: src/features/admin_access_restriction.php:505
234
  #: src/features/comments_filter.php:115 src/features/comments_filter.php:134
235
+ #: src/features/login_protect.php:646 src/features/login_protect.php:665
236
  #: src/features/plugin.php:758 src/features/user_management.php:324
237
  #: src/features/user_management.php:333 src/features/user_management.php:342
238
  #: src/features/user_management.php:351
239
  msgid "Use of this feature is highly recommend."
240
  msgstr ""
241
 
242
+ #: src/features/admin_access_restriction.php:498
243
  msgid "Security Admin Settings"
244
  msgstr ""
245
 
246
+ #: src/features/admin_access_restriction.php:502
247
  msgid "Security Admin Restriction Zones"
248
  msgstr ""
249
 
250
+ #: src/features/admin_access_restriction.php:504
251
  msgid ""
252
  "Restricts access to key WordPress areas for all users not authenticated with "
253
  "the Security Admin Access system."
254
  msgstr ""
255
 
256
+ #: src/features/admin_access_restriction.php:507
257
  msgid "Access Restriction Zones"
258
  msgstr ""
259
 
260
+ #: src/features/admin_access_restriction.php:511
261
+ #: src/features/admin_access_restriction.php:524
262
+ #: src/features/admin_access_restriction.php:619
263
  msgid "White Label"
264
  msgstr ""
265
 
266
+ #: src/features/admin_access_restriction.php:515
267
  #, php-format
268
  msgid "Rename and re-brand the %s plugin for your client site installations."
269
  msgstr ""
270
 
271
+ #: src/features/admin_access_restriction.php:519
272
+ #: src/features/login_protect.php:756
273
+ #: src/processors/loginprotect_backupcodes.php:33
274
  msgid "Important"
275
  msgstr ""
276
 
277
+ #: src/features/admin_access_restriction.php:520
278
  msgid "The Security Admin system must be active for these settings to apply."
279
  msgstr ""
280
 
281
+ #: src/features/admin_access_restriction.php:548
282
  #: src/features/audit_trail.php:338 src/features/autoupdates.php:251
283
  #: src/features/comments_filter.php:188 src/features/firewall.php:115
284
  #: src/features/hack_protect.php:842 src/features/headers.php:166
285
  #: src/features/ips.php:347 src/features/lockdown.php:140
286
+ #: src/features/login_protect.php:698 src/features/plugin.php:805
287
  #: src/features/sessions.php:79 src/features/statistics.php:99
288
+ #: src/features/statistics.php:105 src/features/traffic.php:502
289
  #: src/features/user_management.php:376
290
  #, php-format
291
  msgid "Enable %s Module"
292
  msgstr ""
293
 
294
+ #: src/features/admin_access_restriction.php:549
295
  msgid "Enforce Security Admin Access Restriction"
296
  msgstr ""
297
 
298
+ #: src/features/admin_access_restriction.php:550
299
  msgid ""
300
  "Enable this with great care and consideration. Ensure that you set a key "
301
  "that you have set an access key that you will remember."
302
  msgstr ""
303
 
304
+ #: src/features/admin_access_restriction.php:554
305
  msgid "Security Admin Access Key"
306
  msgstr ""
307
 
308
+ #: src/features/admin_access_restriction.php:555
309
  msgid "Provide/Update Security Admin Access Key"
310
  msgstr ""
311
 
312
+ #: src/features/admin_access_restriction.php:556
313
+ #: src/features/admin_access_restriction.php:577
314
+ #: src/features/admin_access_restriction.php:584
315
+ #: src/features/admin_access_restriction.php:591
316
+ #: src/features/admin_access_restriction.php:597
317
+ #: src/features/admin_access_restriction.php:603
318
  msgid "Careful"
319
  msgstr ""
320
 
321
+ #: src/features/admin_access_restriction.php:556
322
  msgid ""
323
  "If you forget this, you could potentially lock yourself out from using this "
324
  "plugin."
325
  msgstr ""
326
 
327
+ #: src/features/admin_access_restriction.php:557
328
  msgid "Security Key Currently Set"
329
  msgstr ""
330
 
331
+ #: src/features/admin_access_restriction.php:557
332
  msgid "Security Key NOT Currently Set"
333
  msgstr ""
334
 
335
+ #: src/features/admin_access_restriction.php:558
336
  #, php-format
337
  msgid "To delete the current security key, type exactly \"%s\" and save."
338
  msgstr ""
339
 
340
+ #: src/features/admin_access_restriction.php:562
341
  msgid "Security Admin Timeout"
342
  msgstr ""
343
 
344
+ #: src/features/admin_access_restriction.php:563
345
  msgid "Specify An Automatic Timeout Interval For Security Admin Access"
346
  msgstr ""
347
 
348
+ #: src/features/admin_access_restriction.php:564
349
  msgid "This will automatically expire your Security Admin Session."
350
  msgstr ""
351
 
352
+ #: src/features/admin_access_restriction.php:568
353
  #: src/features/hack_protect.php:850 src/features/hack_protect.php:916
354
+ #: src/features/login_protect.php:784 src/features/login_protect.php:827
355
+ #: src/features/login_protect.php:834 src/features/user_management.php:399
356
  msgid "Default"
357
  msgstr ""
358
 
359
+ #: src/features/admin_access_restriction.php:575
360
  msgid "Pages"
361
  msgstr ""
362
 
363
+ #: src/features/admin_access_restriction.php:576
364
  msgid "Restrict Access To Key WordPress Posts And Pages Actions"
365
  msgstr ""
366
 
367
+ #: src/features/admin_access_restriction.php:577
368
  msgid "This will restrict access to page/post creation, editing and deletion."
369
  msgstr ""
370
 
371
+ #: src/features/admin_access_restriction.php:578
372
+ #: src/features/admin_access_restriction.php:585
373
+ #: src/features/admin_access_restriction.php:606
374
  #: src/features/comments_filter.php:126 src/features/headers.php:239
375
+ #: src/features/login_protect.php:618 src/features/login_protect.php:647
376
+ #: src/features/login_protect.php:656 src/features/login_protect.php:674
377
+ #: src/features/login_protect.php:747 src/features/login_protect.php:755
378
+ #: src/features/login_protect.php:769 src/features/plugin.php:759
379
  #: src/features/plugin.php:763 src/features/plugin.php:857
380
  msgid "Note"
381
  msgstr ""
382
 
383
+ #: src/features/admin_access_restriction.php:578
384
+ #: src/features/admin_access_restriction.php:585
385
+ #: src/features/admin_access_restriction.php:608
386
  #, php-format
387
  msgid "Selecting \"%s\" will also restrict all other options."
388
  msgstr ""
389
 
390
+ #: src/features/admin_access_restriction.php:578
391
  msgid "Edit"
392
  msgstr ""
393
 
394
+ #: src/features/admin_access_restriction.php:582
395
  #: src/features/audit_trail.php:187 src/features/audit_trail.php:362
396
  #: src/features/audit_trail.php:363 src/features/autoupdates.php:282
397
  #: src/features/hack_protect.php:728 src/features/insights.php:330
399
  msgid "Plugins"
400
  msgstr ""
401
 
402
+ #: src/features/admin_access_restriction.php:583
403
  msgid "Restrict Access To Key WordPress Plugin Actions"
404
  msgstr ""
405
 
406
+ #: src/features/admin_access_restriction.php:584
407
  msgid ""
408
  "This will restrict access to plugin installation, update, activation and "
409
  "deletion."
410
  msgstr ""
411
 
412
+ #: src/features/admin_access_restriction.php:585
413
+ #: src/features/admin_access_restriction.php:611
414
  msgid "Activate"
415
  msgstr ""
416
 
417
+ #: src/features/admin_access_restriction.php:589
418
  msgid "WordPress Options"
419
  msgstr ""
420
 
421
+ #: src/features/admin_access_restriction.php:590
422
  msgid "Restrict Access To Certain WordPress Admin Options"
423
  msgstr ""
424
 
425
+ #: src/features/admin_access_restriction.php:591
426
  msgid ""
427
  "This will restrict the ability of WordPress administrators from changing key "
428
  "WordPress settings."
429
  msgstr ""
430
 
431
+ #: src/features/admin_access_restriction.php:595
432
  msgid "Admin Users"
433
  msgstr ""
434
 
435
+ #: src/features/admin_access_restriction.php:596
436
  msgid "Restrict Access To Create/Delete/Modify Other Admin Users"
437
  msgstr ""
438
 
439
+ #: src/features/admin_access_restriction.php:597
440
  msgid ""
441
  "This will restrict the ability of WordPress administrators from creating, "
442
  "modifying or promoting other administrators."
443
  msgstr ""
444
 
445
+ #: src/features/admin_access_restriction.php:601
446
  #: src/features/audit_trail.php:188 src/features/audit_trail.php:368
447
  #: src/features/audit_trail.php:369 src/features/autoupdates.php:294
448
  #: src/features/insights.php:376 src/features/insights.php:387
449
  msgid "Themes"
450
  msgstr ""
451
 
452
+ #: src/features/admin_access_restriction.php:602
453
  msgid "Restrict Access To WordPress Theme Actions"
454
  msgstr ""
455
 
456
+ #: src/features/admin_access_restriction.php:603
457
  msgid ""
458
  "This will restrict access to theme installation, update, activation and "
459
  "deletion."
460
  msgstr ""
461
 
462
+ #: src/features/admin_access_restriction.php:610
463
  #, php-format
464
  msgid "%s and %s"
465
  msgstr ""
466
 
467
+ #: src/features/admin_access_restriction.php:612
468
  msgid "Edit Theme Options"
469
  msgstr ""
470
 
471
+ #: src/features/admin_access_restriction.php:620
472
  msgid "Activate Your White Label Settings"
473
  msgstr ""
474
 
475
+ #: src/features/admin_access_restriction.php:621
476
  msgid "Turn on/off the application of your White Label settings."
477
  msgstr ""
478
 
479
+ #: src/features/admin_access_restriction.php:624
480
  msgid "Hide Updates"
481
  msgstr ""
482
 
483
+ #: src/features/admin_access_restriction.php:625
484
  msgid "Hide Plugin Updates From Non-Security Admins"
485
  msgstr ""
486
 
487
+ #: src/features/admin_access_restriction.php:626
488
  #, php-format
489
  msgid "Hide available %s updates from non-security administrators."
490
  msgstr ""
491
 
492
+ #: src/features/admin_access_restriction.php:629
493
+ #: src/features/admin_access_restriction.php:636
494
  msgid "Plugin Name"
495
  msgstr ""
496
 
497
+ #: src/features/admin_access_restriction.php:630
498
  msgid "The Name Of The Plugin"
499
  msgstr ""
500
 
501
+ #: src/features/admin_access_restriction.php:631
502
  msgid "The name of the plugin that will be displayed to your site users."
503
  msgstr ""
504
 
505
+ #: src/features/admin_access_restriction.php:634
506
  msgid "Menu Title"
507
  msgstr ""
508
 
509
+ #: src/features/admin_access_restriction.php:635
510
  msgid "The Main Menu Title Of The Plugin"
511
  msgstr ""
512
 
513
+ #: src/features/admin_access_restriction.php:636
514
  #, php-format
515
  msgid ""
516
  "The Main Menu Title Of The Plugin. If left empty, the \"%s\" will be used."
517
  msgstr ""
518
 
519
+ #: src/features/admin_access_restriction.php:639
520
  msgid "Company Name"
521
  msgstr ""
522
 
523
+ #: src/features/admin_access_restriction.php:640
524
  msgid "The Name Of Your Company"
525
  msgstr ""
526
 
527
+ #: src/features/admin_access_restriction.php:641
528
  msgid "Provide the name of your company."
529
  msgstr ""
530
 
531
+ #: src/features/admin_access_restriction.php:644
532
  msgid "Description"
533
  msgstr ""
534
 
535
+ #: src/features/admin_access_restriction.php:645
536
  msgid "The Description Of The Plugin"
537
  msgstr ""
538
 
539
+ #: src/features/admin_access_restriction.php:646
540
  msgid "The description of the plugin displayed on the plugins page."
541
  msgstr ""
542
 
543
+ #: src/features/admin_access_restriction.php:649
544
  msgid "Home URL"
545
  msgstr ""
546
 
547
+ #: src/features/admin_access_restriction.php:650
548
  msgid "Plugin Home Page URL"
549
  msgstr ""
550
 
551
+ #: src/features/admin_access_restriction.php:651
552
  msgid ""
553
  "When a user clicks the home link for this plugin, this is where they'll be "
554
  "directed."
555
  msgstr ""
556
 
557
+ #: src/features/admin_access_restriction.php:654
558
  msgid "Menu Icon"
559
  msgstr ""
560
 
561
+ #: src/features/admin_access_restriction.php:655
562
  msgid "Menu Icon URL"
563
  msgstr ""
564
 
565
+ #: src/features/admin_access_restriction.php:656
566
  msgid "The URL of the icon to display in the menu."
567
  msgstr ""
568
 
569
+ #: src/features/admin_access_restriction.php:657
570
+ #: src/features/admin_access_restriction.php:663
571
  #, php-format
572
  msgid "The %s should measure %s."
573
  msgstr ""
574
 
575
+ #: src/features/admin_access_restriction.php:657
576
  msgid "icon"
577
  msgstr ""
578
 
579
+ #: src/features/admin_access_restriction.php:660
580
  msgid "Dashboard Logo"
581
  msgstr ""
582
 
583
+ #: src/features/admin_access_restriction.php:661
584
  msgid "Dashboard Logo URL"
585
  msgstr ""
586
 
587
+ #: src/features/admin_access_restriction.php:662
588
  msgid "The URL of the logo to display in the admin pages."
589
  msgstr ""
590
 
591
+ #: src/features/admin_access_restriction.php:663
592
  msgid "logo"
593
  msgstr ""
594
 
595
+ #: src/features/admin_access_restriction.php:666
596
+ #: src/features/admin_access_restriction.php:667
597
+ msgid "2FA Login Logo URL"
598
+ msgstr ""
599
+
600
+ #: src/features/admin_access_restriction.php:668
601
+ msgid ""
602
+ "The URL of the logo to display on the Two-Factor Authentication login page."
603
+ msgstr ""
604
+
605
  #: src/features/audit_trail.php:139
606
  msgid "Your IP"
607
  msgstr ""
608
 
609
  #: src/features/audit_trail.php:169 src/features/audit_trail.php:183
610
+ #: src/features/license.php:94 src/features/plugin.php:950
611
  msgid "Audit Trail Viewer"
612
  msgstr ""
613
 
614
+ #: src/features/audit_trail.php:184 src/features/license.php:95
615
  msgid "Review audit trail logs "
616
  msgstr ""
617
 
645
  msgstr ""
646
 
647
  #: src/features/audit_trail.php:195 src/features/user_management.php:157
648
+ #: src/processors/loginprotect_backupcodes.php:175
649
  #: src/processors/loginprotect_twofactorauth.php:161
650
  #: src/processors/user_management.php:208
651
  #: src/processors/user_management.php:236
657
  msgstr ""
658
 
659
  #: src/features/audit_trail.php:197 src/features/plugin.php:937
660
+ #: src/processors/firewall.php:477
661
+ #: src/processors/loginprotect_backupcodes.php:176
662
  #: src/processors/loginprotect_twofactorauth.php:162
663
  #: src/processors/user_management.php:210
664
  #: src/processors/user_management.php:237
665
  msgid "IP Address"
666
  msgstr ""
667
 
668
+ #: src/features/audit_trail.php:198 src/features/traffic.php:391
669
  msgid "You"
670
  msgstr ""
671
 
698
  msgstr ""
699
 
700
  #: src/features/audit_trail.php:302 src/features/audit_trail.php:311
701
+ #: src/features/traffic.php:477
702
  msgid "These settings are dependent on your requirements."
703
  msgstr ""
704
 
717
  #: src/features/audit_trail.php:339 src/features/autoupdates.php:252
718
  #: src/features/firewall.php:116 src/features/hack_protect.php:843
719
  #: src/features/headers.php:167 src/features/ips.php:348
720
+ #: src/features/lockdown.php:141 src/features/login_protect.php:699
721
  #: src/features/sessions.php:80 src/features/statistics.php:100
722
+ #: src/features/statistics.php:106 src/features/traffic.php:503
723
  #: src/features/user_management.php:377
724
  #, php-format
725
  msgid "Enable (or Disable) The %s Module"
729
  #: src/features/comments_filter.php:190 src/features/firewall.php:117
730
  #: src/features/hack_protect.php:844 src/features/headers.php:168
731
  #: src/features/ips.php:349 src/features/lockdown.php:142
732
+ #: src/features/login_protect.php:700 src/features/sessions.php:81
733
  #: src/features/statistics.php:101 src/features/statistics.php:107
734
+ #: src/features/traffic.php:504 src/features/user_management.php:378
735
  #, php-format
736
  msgid "Un-Checking this option will completely disable the %s module."
737
  msgstr ""
1113
  #: src/processors/hackprotect_corechecksumscan.php:280
1114
  #: src/processors/hackprotect_pluginvulnerabilities.php:156
1115
  #: src/processors/hackprotect_wpvulnscan.php:147
1116
+ #: src/processors/loginprotect_intent.php:293
1117
  msgid "More Info"
1118
  msgstr ""
1119
 
1192
  msgid "Nonce security checking failed - the nonce supplied was \"%s\"."
1193
  msgstr ""
1194
 
1195
+ #: src/features/base_wpsf.php:319 src/features/base_wpsf.php:320
1196
  msgid "User Messages"
1197
  msgstr ""
1198
 
1199
+ #: src/features/base_wpsf.php:322
1200
  msgid "Customize the messages displayed to the user."
1201
  msgstr ""
1202
 
1203
+ #: src/features/base_wpsf.php:323
1204
  msgid ""
1205
  "Use this section if you need to communicate to the user in a particular "
1206
  "manner."
1207
  msgstr ""
1208
 
1209
+ #: src/features/base_wpsf.php:324
1210
  msgid "Hint"
1211
  msgstr ""
1212
 
1213
+ #: src/features/base_wpsf.php:324
1214
  #, php-format
1215
  msgid "To reset any message to its default, enter the text exactly: %s"
1216
  msgstr ""
1269
  msgid "Adds Google reCAPTCHA to the Comment Forms."
1270
  msgstr ""
1271
 
1272
+ #: src/features/comments_filter.php:125 src/features/login_protect.php:617
1273
  msgid "Keep this turned on."
1274
  msgstr ""
1275
 
1276
+ #: src/features/comments_filter.php:126 src/features/login_protect.php:618
1277
  msgid ""
1278
  "You will need to register for Google reCAPTCHA keys and store them in the "
1279
  "Shield 'Dashboard' settings."
1444
  msgid "Use Google reCAPTCHA on the comments form to prevent bot-spam comments."
1445
  msgstr ""
1446
 
1447
+ #: src/features/comments_filter.php:249 src/features/login_protect.php:760
1448
  #: src/features/plugin.php:907
1449
  msgid "reCAPTCHA Style"
1450
  msgstr ""
1451
 
1452
+ #: src/features/comments_filter.php:250 src/features/login_protect.php:761
1453
  msgid "How Google reCAPTCHA Will Be Displayed"
1454
  msgstr ""
1455
 
1456
+ #: src/features/comments_filter.php:251 src/features/login_protect.php:762
1457
  #: src/features/plugin.php:909
1458
  msgid ""
1459
  "You can choose the reCAPTCHA display format that best suits your site, "
1642
  "%s, etc)."
1643
  msgstr ""
1644
 
1645
+ #: src/features/firewall.php:133 src/processors/firewall.php:545
1646
  msgid "SQL Queries"
1647
  msgstr ""
1648
 
1655
  msgid "This will block sql in application parameters (e.g. %s, etc)."
1656
  msgstr ""
1657
 
1658
+ #: src/features/firewall.php:139 src/processors/firewall.php:539
1659
  msgid "WordPress Terms"
1660
  msgstr ""
1661
 
1669
  "user_login, etc.)."
1670
  msgstr ""
1671
 
1672
+ #: src/features/firewall.php:145 src/processors/firewall.php:542
1673
  msgid "Field Truncation"
1674
  msgstr ""
1675
 
1681
  msgid "This will block field truncation attacks in application parameters."
1682
  msgstr ""
1683
 
1684
+ #: src/features/firewall.php:151 src/processors/firewall.php:554
1685
  msgid "PHP Code"
1686
  msgstr ""
1687
 
1750
  #: src/processors/hackprotect_corechecksumscan.php:244
1751
  #: src/processors/hackprotect_filecleanerscan.php:232
1752
  #: src/processors/hackprotect_pluginvulnerabilities.php:110
1753
+ #: src/processors/hackprotect_ptguard.php:526
1754
  #: src/processors/hackprotect_wpvulnscan.php:220
1755
  #: src/processors/loginprotect_wplogin.php:74
1756
  #: src/processors/loginprotect_wplogin.php:93 src/processors/plugin.php:206
1813
  msgstr ""
1814
 
1815
  #: src/features/firewall.php:195 src/features/firewall.php:196
1816
+ #: src/features/login_protect.php:165
1817
  msgid "Administrators"
1818
  msgstr ""
1819
 
1854
  msgid "%s per day"
1855
  msgstr ""
1856
 
1857
+ #: src/features/hack_protect.php:618 src/features/license.php:42
1858
  msgid "Never"
1859
  msgstr ""
1860
 
2246
  msgstr ""
2247
 
2248
  #: src/features/hack_protect.php:935 src/features/headers.php:197
2249
+ #: src/features/headers.php:198 src/features/login_protect.php:714
2250
+ #: src/features/login_protect.php:732 src/features/login_protect.php:738
2251
  #: src/features/plugin.php:799
2252
  #, php-format
2253
  msgid "Enable %s"
2692
  msgid "Pro"
2693
  msgstr ""
2694
 
2695
+ #: src/features/insights.php:525 src/features/traffic.php:365
2696
  msgid "Yes"
2697
  msgstr ""
2698
 
2699
+ #: src/features/insights.php:525 src/features/traffic.php:341
2700
+ #: src/features/traffic.php:365
2701
  msgid "No"
2702
  msgstr ""
2703
 
2951
  "the White List"
2952
  msgstr ""
2953
 
2954
+ #: src/features/license.php:39 src/features/license.php:98
2955
+ msgid "Active"
2956
+ msgstr ""
2957
+
2958
+ #: src/features/license.php:39
2959
+ msgid "Not Active"
2960
  msgstr ""
2961
 
2962
  #: src/features/license.php:97
2963
+ msgid "Name"
2964
  msgstr ""
2965
 
2966
+ #: src/features/license.php:99
2967
  msgid "Status"
2968
  msgstr ""
2969
 
2970
+ #: src/features/license.php:100
2971
  msgid "Key"
2972
  msgstr ""
2973
 
2974
+ #: src/features/license.php:101
2975
  msgid "Expires"
2976
  msgstr ""
2977
 
2978
+ #: src/features/license.php:102
2979
  msgid "Owner"
2980
  msgstr ""
2981
 
2982
+ #: src/features/license.php:103
2983
  msgid "Checked"
2984
  msgstr ""
2985
 
2986
+ #: src/features/license.php:104
2987
  msgid "Error"
2988
  msgstr ""
2989
 
2990
+ #: src/features/license.php:176
2991
  #, php-format
2992
  msgid "Please wait %s before attempting another license check."
2993
  msgstr ""
2994
 
2995
+ #: src/features/license.php:177
2996
  #, php-format
2997
  msgid "%s second"
2998
  msgid_plural "%s seconds"
2999
  msgstr[0] ""
3000
  msgstr[1] ""
3001
 
3002
+ #: src/features/license.php:183
3003
  msgid "Valid license found."
3004
  msgstr ""
3005
 
3006
+ #: src/features/license.php:183
3007
  msgid "Valid license couldn't be found."
3008
  msgstr ""
3009
 
3010
+ #: src/features/license.php:305
3011
  #, php-format
3012
  msgid "Automatic license verification failed after %s days."
3013
  msgstr ""
3014
 
3015
+ #: src/features/license.php:351
3016
  msgid "Attempts to verify Shield Pro license has just failed."
3017
  msgstr ""
3018
 
3019
+ #: src/features/license.php:352 src/features/license.php:369
3020
  #, php-format
3021
  msgid "Please check your license on-site: %s"
3022
  msgstr ""
3023
 
3024
+ #: src/features/license.php:353 src/features/license.php:370
3025
  #, php-format
3026
  msgid "If this problem persists, please contact support: %s"
3027
  msgstr ""
3028
 
3029
+ #: src/features/license.php:368
3030
  msgid "All attempts to verify Shield Pro license have failed."
3031
  msgstr ""
3032
 
3033
+ #: src/features/license.php:688 src/features/license.php:689
3034
  msgid "License Options"
3035
  msgstr ""
3036
 
3037
+ #: src/features/license.php:691
3038
  #, php-format
3039
  msgid "Activate %s Pro Extensions."
3040
  msgstr ""
3041
 
3042
+ #: src/features/license.php:692
3043
  msgid "TODO."
3044
  msgstr ""
3045
 
3046
+ #: src/features/license.php:716 src/features/license.php:717
3047
+ #: src/features/license.php:718
3048
  msgid "License Key"
3049
  msgstr ""
3050
 
3247
  msgid "Email verification could not be completed."
3248
  msgstr ""
3249
 
3250
+ #: src/features/login_protect.php:86
3251
  msgid ""
3252
  "Before enabling 2-factor email authentication for your WordPress site, you "
3253
  "must verify you can receive this email."
3254
  msgstr ""
3255
 
3256
+ #: src/features/login_protect.php:87
3257
  msgid ""
3258
  "This verifies your website can send email and that your account can receive "
3259
  "emails sent from your site."
3260
  msgstr ""
3261
 
3262
+ #: src/features/login_protect.php:92
3263
  #, php-format
3264
  msgid "Click the verify link: %s"
3265
  msgstr ""
3266
 
3267
+ #: src/features/login_protect.php:95
3268
  #, php-format
3269
  msgid "Here's your code for the guided wizard: %s"
3270
  msgstr ""
3271
 
3272
+ #: src/features/login_protect.php:98
3273
  msgid "Email Sending Verification"
3274
  msgstr ""
3275
 
3276
+ #: src/features/login_protect.php:161
3277
  msgid "Subscribers"
3278
  msgstr ""
3279
 
3280
+ #: src/features/login_protect.php:162
3281
  msgid "Contributors"
3282
  msgstr ""
3283
 
3284
+ #: src/features/login_protect.php:163
3285
  msgid "Authors"
3286
  msgstr ""
3287
 
3288
+ #: src/features/login_protect.php:164
3289
  msgid "Editors"
3290
  msgstr ""
3291
 
3292
+ #: src/features/login_protect.php:429
3293
  msgid "I'm a human."
3294
  msgstr ""
3295
 
3296
+ #: src/features/login_protect.php:433
3297
  msgid "Please check the box to show us you're a human."
3298
  msgstr ""
3299
 
3300
+ #: src/features/login_protect.php:468
3301
  #, php-format
3302
  msgid "Support for login protection with %s is a Pro-only feature."
3303
  msgstr ""
3304
 
3305
+ #: src/features/login_protect.php:474
3306
  msgid ""
3307
  "2FA by email demands that your WP site is properly configured to send email."
3308
  msgstr ""
3309
 
3310
+ #: src/features/login_protect.php:475
3311
  msgid ""
3312
  "This is a common problem and you may get locked out in the future if you "
3313
  "ignore this."
3314
  msgstr ""
3315
 
3316
+ #: src/features/login_protect.php:476 src/processors/lockdown.php:219
3317
  #: src/processors/plugin_tracking.php:37
3318
  msgid "Learn More."
3319
  msgstr ""
3320
 
3321
+ #: src/features/login_protect.php:573
3322
+ msgid "Multi-factor login backup code has been removed from your profile"
3323
+ msgstr ""
3324
+
3325
+ #: src/features/login_protect.php:607
3326
  msgid ""
3327
  "Login Guard blocks all automated and brute force attempts to log in to your "
3328
  "site."
3329
  msgstr ""
3330
 
3331
+ #: src/features/login_protect.php:608 src/features/plugin.php:965
3332
  #: src/wizards/plugin.php:561 src/wizards/plugin.php:566
3333
  msgid "Login Guard"
3334
  msgstr ""
3335
 
3336
+ #: src/features/login_protect.php:616
3337
  msgid "Adds Google reCAPTCHA to the Login Forms."
3338
  msgstr ""
3339
 
3340
+ #: src/features/login_protect.php:623
3341
  msgid "Hide WordPress Login Page"
3342
  msgstr ""
3343
 
3344
+ #: src/features/login_protect.php:624
3345
  #, php-format
3346
  msgid "Rename \"%s\""
3347
  msgstr ""
3348
 
3349
+ #: src/features/login_protect.php:625
3350
  msgid "Hide Login Page"
3351
  msgstr ""
3352
 
3353
+ #: src/features/login_protect.php:627
3354
  msgid ""
3355
  "To hide your wp-login.php page from brute force attacks and hacking attempts "
3356
  "- if your login page cannot be found, no-one can login."
3357
  msgstr ""
3358
 
3359
+ #: src/features/login_protect.php:628
3360
  msgid ""
3361
  "This is not required for complete security and if your site has irregular or "
3362
  "inconsistent configuration it may not work for you."
3363
  msgstr ""
3364
 
3365
+ #: src/features/login_protect.php:633 src/features/login_protect.php:714
3366
  #: src/features/user_management.php:344
3367
  msgid "Multi-Factor Authentication"
3368
  msgstr ""
3369
 
3370
+ #: src/features/login_protect.php:634
3371
  msgid "Multi-Factor Auth"
3372
  msgstr ""
3373
 
3374
+ #: src/features/login_protect.php:636 src/features/user_management.php:341
3375
  msgid ""
3376
  "Verifies the identity of users who log in to your site - i.e. they are who "
3377
  "they say they are."
3378
  msgstr ""
3379
 
3380
+ #: src/features/login_protect.php:637 src/features/login_protect.php:647
3381
+ #: src/features/login_protect.php:656 src/features/login_protect.php:674
3382
  msgid "You may combine multiple authentication factors for increased security."
3383
  msgstr ""
3384
 
3385
+ #: src/features/login_protect.php:642
3386
  msgid "Email Two-Factor Authentication"
3387
  msgstr ""
3388
 
3389
+ #: src/features/login_protect.php:643
3390
  msgid "2FA - Email"
3391
  msgstr ""
3392
 
3393
+ #: src/features/login_protect.php:645
3394
  msgid ""
3395
  "Verifies the identity of users who log in to your site using email-based one-"
3396
  "time-passwords."
3397
  msgstr ""
3398
 
3399
+ #: src/features/login_protect.php:646 src/features/user_management.php:342
3400
  msgid "However, if your host blocks email sending you may lock yourself out."
3401
  msgstr ""
3402
 
3403
+ #: src/features/login_protect.php:652
3404
  msgid "Google Authenticator Two-Factor Authentication"
3405
  msgstr ""
3406
 
3407
+ #: src/features/login_protect.php:653
3408
  msgid "2FA - Google Authenticator"
3409
  msgstr ""
3410
 
3411
+ #: src/features/login_protect.php:655
3412
  msgid ""
3413
  "Verifies the identity of users who log in to your site using Google "
3414
  "Authenticator one-time-passwords."
3415
  msgstr ""
3416
 
3417
+ #: src/features/login_protect.php:661
3418
  msgid "Brute Force Login Protection"
3419
  msgstr ""
3420
 
3421
+ #: src/features/login_protect.php:662
3422
  msgid "reCAPTCHA & Bots"
3423
  msgstr ""
3424
 
3425
+ #: src/features/login_protect.php:664
3426
  msgid ""
3427
  "Blocks brute force hacking attacks against your login and registration pages."
3428
  msgstr ""
3429
 
3430
+ #: src/features/login_protect.php:670
3431
  msgid "Yubikey Two-Factor Authentication"
3432
  msgstr ""
3433
 
3434
+ #: src/features/login_protect.php:671
3435
  msgid "2FA -Yubikey"
3436
  msgstr ""
3437
 
3438
+ #: src/features/login_protect.php:673
3439
  msgid ""
3440
  "Verifies the identity of users who log in to your site using Yubikey one-"
3441
  "time-passwords."
3442
  msgstr ""
3443
 
3444
+ #: src/features/login_protect.php:704
3445
  msgid "Hide WP Login Page"
3446
  msgstr ""
3447
 
3448
+ #: src/features/login_protect.php:705
3449
  msgid "Hide The WordPress Login Page"
3450
  msgstr ""
3451
 
3452
+ #: src/features/login_protect.php:706
3453
  msgid "Creating a path here will disable your wp-login.php"
3454
  msgstr ""
3455
 
3456
+ #: src/features/login_protect.php:708
3457
  #, php-format
3458
  msgid "Only letters and numbers are permitted: %s"
3459
  msgstr ""
3460
 
3461
+ #: src/features/login_protect.php:710
3462
  #, php-format
3463
  msgid "Your current login URL is: %s"
3464
  msgstr ""
3465
 
3466
+ #: src/features/login_protect.php:715
3467
  msgid "Require All Active Authentication Factors"
3468
  msgstr ""
3469
 
3470
+ #: src/features/login_protect.php:716
3471
  msgid ""
3472
  "When enabled, all multi-factor authentication methods will be applied to a "
3473
  "user login. Disable to require only one to login."
3474
  msgstr ""
3475
 
3476
+ #: src/features/login_protect.php:720
3477
  msgid "Multi-Factor By-Pass"
3478
  msgstr ""
3479
 
3480
+ #: src/features/login_protect.php:721
3481
  msgid ""
3482
  "A User Can By-Pass Multi-Factor Authentication (MFA) For The Set Number Of "
3483
  "Days"
3484
  msgstr ""
3485
 
3486
+ #: src/features/login_protect.php:722
3487
  msgid ""
3488
  "Enter the number of days a user can by-pass future MFA after a successful "
3489
  "MFA-login. 0 to disable."
3490
  msgstr ""
3491
 
3492
+ #: src/features/login_protect.php:726
3493
+ msgid "Allow Backup Codes"
3494
+ msgstr ""
3495
+
3496
+ #: src/features/login_protect.php:727
3497
+ msgid "Allow Users To Generate A Backup Code"
3498
+ msgstr ""
3499
+
3500
+ #: src/features/login_protect.php:728
3501
+ msgid ""
3502
+ "Allow users to generate a backup code that can be used to login if MFA "
3503
+ "factors are unavailable."
3504
+ msgstr ""
3505
+
3506
+ #: src/features/login_protect.php:732
3507
+ #: src/processors/loginprotect_backupcodes.php:40
3508
  #: src/processors/loginprotect_googleauthenticator.php:41
3509
  #: src/processors/loginprotect_googleauthenticator.php:45
3510
  #: src/processors/loginprotect_googleauthenticator.php:47
3511
+ #: src/processors/loginprotect_googleauthenticator.php:184
3512
+ #: src/processors/loginprotect_googleauthenticator.php:289
3513
+ #: src/processors/loginprotect_googleauthenticator.php:297
3514
  msgid "Google Authenticator"
3515
  msgstr ""
3516
 
3517
+ #: src/features/login_protect.php:733
3518
  msgid "Allow Users To Use Google Authenticator"
3519
  msgstr ""
3520
 
3521
+ #: src/features/login_protect.php:734
3522
  msgid ""
3523
  "When enabled, users will have the option to add Google Authenticator to "
3524
  "their WordPress user profile"
3525
  msgstr ""
3526
 
3527
+ #: src/features/login_protect.php:738 src/features/login_protect.php:744
3528
+ #: src/features/login_protect.php:747
3529
  #: src/processors/loginprotect_twofactorauth.php:201
3530
  #: src/processors/loginprotect_twofactorauth.php:202
3531
  msgid "Email Authentication"
3532
  msgstr ""
3533
 
3534
+ #: src/features/login_protect.php:739
3535
  #, php-format
3536
  msgid "Two-Factor Login Authentication By %s"
3537
  msgstr ""
3538
 
3539
+ #: src/features/login_protect.php:739 src/features/plugin.php:955
3540
  #: src/processors/user_management.php:209
3541
  msgid "Email"
3542
  msgstr ""
3543
 
3544
+ #: src/features/login_protect.php:740
3545
  msgid ""
3546
  "All users will be required to verify their login by email-based two-factor "
3547
  "authentication."
3548
  msgstr ""
3549
 
3550
+ #: src/features/login_protect.php:744
3551
  msgid "Enforce"
3552
  msgstr ""
3553
 
3554
+ #: src/features/login_protect.php:745
3555
  msgid "All User Roles Subject To Email Authentication"
3556
  msgstr ""
3557
 
3558
+ #: src/features/login_protect.php:746
3559
  msgid ""
3560
  "Enforces email-based authentication on all users with the selected roles."
3561
  msgstr ""
3562
 
3563
+ #: src/features/login_protect.php:747
3564
  #, php-format
3565
  msgid "This setting only applies to %s."
3566
  msgstr ""
3567
 
3568
+ #: src/features/login_protect.php:751
3569
  msgid "Google reCAPTCHA"
3570
  msgstr ""
3571
 
3572
+ #: src/features/login_protect.php:752
3573
  msgid "Protect WordPress Account Access Requests With Google reCAPTCHA"
3574
  msgstr ""
3575
 
3576
+ #: src/features/login_protect.php:753
3577
  msgid ""
3578
  "Use Google reCAPTCHA on the user account forms such as login, register, etc."
3579
  msgstr ""
3580
 
3581
+ #: src/features/login_protect.php:754
3582
  #, php-format
3583
  msgid "Use of any theme other than \"%s\", requires a Pro license."
3584
  msgstr ""
3585
 
3586
+ #: src/features/login_protect.php:754
3587
  msgid "Light Theme"
3588
  msgstr ""
3589
 
3590
+ #: src/features/login_protect.php:755
3591
  msgid ""
3592
  "You'll need to setup your Google reCAPTCHA API Keys in 'General' settings."
3593
  msgstr ""
3594
 
3595
+ #: src/features/login_protect.php:756
3596
  msgid ""
3597
  "Some forms are more dynamic than others so if you experience problems, "
3598
  "please use non-Invisible reCAPTCHA."
3599
  msgstr ""
3600
 
3601
+ #: src/features/login_protect.php:766
3602
  msgid "Protection Locations"
3603
  msgstr ""
3604
 
3605
+ #: src/features/login_protect.php:767
3606
  msgid "Which Forms Should Be Protected"
3607
  msgstr ""
3608
 
3609
+ #: src/features/login_protect.php:768
3610
  msgid "Choose the forms for which bot protection measures will be deployed."
3611
  msgstr ""
3612
 
3613
+ #: src/features/login_protect.php:769
3614
  #, php-format
3615
  msgid "Use with 3rd party systems such as %s, requires a Pro license."
3616
  msgstr ""
3617
 
3618
+ #: src/features/login_protect.php:773
3619
  msgid "Bot Protection"
3620
  msgstr ""
3621
 
3622
+ #: src/features/login_protect.php:774
3623
  msgid "Protect WP Login From Automated Login Attempts By Bots"
3624
  msgstr ""
3625
 
3626
+ #: src/features/login_protect.php:775
3627
  msgid ""
3628
  "Adds a dynamically (Javascript) generated checkbox to the login form that "
3629
  "prevents bots using automated login techniques."
3630
  msgstr ""
3631
 
3632
+ #: src/features/login_protect.php:776
3633
  msgid "ON"
3634
  msgstr ""
3635
 
3636
+ #: src/features/login_protect.php:780
3637
  msgid "Cooldown Period"
3638
  msgstr ""
3639
 
3640
+ #: src/features/login_protect.php:781
3641
  msgid "Limit account access requests to every X seconds"
3642
  msgstr ""
3643
 
3644
+ #: src/features/login_protect.php:782
3645
  msgid ""
3646
  "WordPress will process only ONE account access attempt per number of seconds "
3647
  "specified."
3648
  msgstr ""
3649
 
3650
+ #: src/features/login_protect.php:783
3651
  msgid "Zero (0) turns this off."
3652
  msgstr ""
3653
 
3654
+ #: src/features/login_protect.php:789
3655
  msgid "User Registration"
3656
  msgstr ""
3657
 
3658
+ #: src/features/login_protect.php:790
3659
  msgid "Apply Brute Force Protection To User Registration And Lost Passwords"
3660
  msgstr ""
3661
 
3662
+ #: src/features/login_protect.php:791
3663
  msgid ""
3664
  "When enabled, settings in this section will also apply to new user "
3665
  "registration and users trying to reset passwords."
3666
  msgstr ""
3667
 
3668
+ #: src/features/login_protect.php:795
3669
  msgid "Enable Yubikey Authentication"
3670
  msgstr ""
3671
 
3672
+ #: src/features/login_protect.php:796
3673
  msgid "Turn On / Off Yubikey Authentication On This Site"
3674
  msgstr ""
3675
 
3676
+ #: src/features/login_protect.php:797
3677
  msgid ""
3678
  "Combined with your Yubikey API details this will form the basis of your "
3679
  "Yubikey Authentication"
3680
  msgstr ""
3681
 
3682
+ #: src/features/login_protect.php:801
3683
  msgid "Yubikey App ID"
3684
  msgstr ""
3685
 
3686
+ #: src/features/login_protect.php:802
3687
  msgid "Your Unique Yubikey App ID"
3688
  msgstr ""
3689
 
3690
+ #: src/features/login_protect.php:803
3691
  msgid ""
3692
  "Combined with your Yubikey API Key this will form the basis of your Yubikey "
3693
  "Authentication"
3694
  msgstr ""
3695
 
3696
+ #: src/features/login_protect.php:804
3697
  msgid ""
3698
  "Please review the info link on how to obtain your own Yubikey App ID and API "
3699
  "Key."
3700
  msgstr ""
3701
 
3702
+ #: src/features/login_protect.php:808
3703
  msgid "Yubikey API Key"
3704
  msgstr ""
3705
 
3706
+ #: src/features/login_protect.php:809
3707
  msgid "Your Unique Yubikey App API Key"
3708
  msgstr ""
3709
 
3710
+ #: src/features/login_protect.php:810
3711
  msgid ""
3712
  "Combined with your Yubikey App ID this will form the basis of your Yubikey "
3713
  "Authentication."
3714
  msgstr ""
3715
 
3716
+ #: src/features/login_protect.php:811
3717
  msgid ""
3718
  "Please review the info link on how to get your own Yubikey App ID and API "
3719
  "Key."
3720
  msgstr ""
3721
 
3722
+ #: src/features/login_protect.php:815
3723
  msgid "Yubikey Unique Keys"
3724
  msgstr ""
3725
 
3726
+ #: src/features/login_protect.php:816
3727
  msgid ""
3728
  "This method for Yubikeys is no longer supported. Please see your user profile"
3729
  msgstr ""
3730
 
3731
+ #: src/features/login_protect.php:817
3732
  msgid "Format"
3733
  msgstr ""
3734
 
3735
+ #: src/features/login_protect.php:818
3736
  msgid "Provide Username<->Yubikey Pairs that are usable for this site."
3737
  msgstr ""
3738
 
3739
+ #: src/features/login_protect.php:819
3740
  msgid ""
3741
  "If a Username if not assigned a Yubikey, Yubikey Authentication is OFF for "
3742
  "that user."
3743
  msgstr ""
3744
 
3745
+ #: src/features/login_protect.php:820
3746
  msgid ""
3747
  "Each [Username,Key] pair should be separated by a new line: you only need to "
3748
  "provide the first 12 characters of the yubikey."
3749
  msgstr ""
3750
 
3751
+ #: src/features/login_protect.php:824
3752
  msgid "GASP Checkbox Text"
3753
  msgstr ""
3754
 
3755
+ #: src/features/login_protect.php:825
3756
  msgid "The User Message Displayed Next To The GASP Checkbox"
3757
  msgstr ""
3758
 
3759
+ #: src/features/login_protect.php:826
3760
  msgid ""
3761
  "You can change the text displayed to the user beside the checkbox if you "
3762
  "need a custom message."
3763
  msgstr ""
3764
 
3765
+ #: src/features/login_protect.php:831
3766
  msgid "GASP Alert Text"
3767
  msgstr ""
3768
 
3769
+ #: src/features/login_protect.php:832
3770
  msgid "The Message Displayed If The User Doesn't Check The Box"
3771
  msgstr ""
3772
 
3773
+ #: src/features/login_protect.php:833
3774
  msgid ""
3775
  "You can change the text displayed to the user in the alert message if they "
3776
  "don't check the box."
4197
  msgid "Cookie"
4198
  msgstr ""
4199
 
4200
+ #: src/features/plugin.php:938 src/features/traffic.php:395
4201
  msgid "IP"
4202
  msgstr ""
4203
 
4306
  msgstr ""
4307
 
4308
  #: src/features/plugin.php:974 src/features/sessions.php:54
4309
+ #: src/features/traffic.php:477 src/features/user_management.php:314
4310
  msgid "User Management"
4311
  msgstr ""
4312
 
4360
  msgid "Sharing"
4361
  msgstr ""
4362
 
4363
+ #: src/features/traffic.php:72
4364
  #, php-format
4365
  msgid "%s is a Pro-only feature."
4366
  msgstr ""
4367
 
4368
+ #: src/features/traffic.php:72
4369
  msgid "Traffic Watch"
4370
  msgstr ""
4371
 
4372
+ #: src/features/traffic.php:77
4373
  msgid ""
4374
  "Traffic Watcher will not run because visitor IP address detection is not "
4375
  "correctly configured."
4376
  msgstr ""
4377
 
4378
+ #: src/features/traffic.php:198
4379
  msgid "Traffic Watch Viewer"
4380
  msgstr ""
4381
 
4382
+ #: src/features/traffic.php:374
4383
  msgid "unknown"
4384
  msgstr ""
4385
 
4386
+ #: src/features/traffic.php:382 src/processors/firewall.php:271
4387
  msgid "Unknown"
4388
  msgstr ""
4389
 
4390
+ #: src/features/traffic.php:396
4391
  msgid "Logged-In"
4392
  msgstr ""
4393
 
4394
+ #: src/features/traffic.php:397
4395
  msgid "Location"
4396
  msgstr ""
4397
 
4398
+ #: src/features/traffic.php:398
4399
  msgid "User Agent"
4400
  msgstr ""
4401
 
4402
+ #: src/features/traffic.php:403
4403
  msgid "Response"
4404
  msgstr ""
4405
 
4406
+ #: src/features/traffic.php:404
4407
  msgid "Transgression"
4408
  msgstr ""
4409
 
4410
+ #: src/features/traffic.php:448
4411
  msgid "Traffic Watch Log"
4412
  msgstr ""
4413
 
4414
+ #: src/features/traffic.php:449
4415
  msgid "Review Site Traffic Logs "
4416
  msgstr ""
4417
 
4418
+ #: src/features/traffic.php:467
4419
  msgid "Monitor and review all requests to your site."
4420
  msgstr ""
4421
 
4422
+ #: src/features/traffic.php:468
4423
  msgid ""
4424
  "Required only if you need to review and investigate and monitor requests to "
4425
  "your site"
4426
  msgstr ""
4427
 
4428
+ #: src/features/traffic.php:474
4429
  msgid "Traffic Watch Options"
4430
  msgstr ""
4431
 
4432
+ #: src/features/traffic.php:476
4433
  msgid "Provides finer control over the Traffic Watch system."
4434
  msgstr ""
4435
 
4436
+ #: src/features/traffic.php:479
4437
  msgid "Traffic Logging Options"
4438
  msgstr ""
4439
 
4440
+ #: src/features/traffic.php:508
4441
  msgid "Traffic Log Exclusions"
4442
  msgstr ""
4443
 
4444
+ #: src/features/traffic.php:509
4445
  msgid "Select Which Types Of Requests To Exclude"
4446
  msgstr ""
4447
 
4448
+ #: src/features/traffic.php:510
4449
  msgid ""
4450
  "Select request types that you don't want to appear in the traffic viewer."
4451
  msgstr ""
4452
 
4453
+ #: src/features/traffic.php:511
4454
  msgid ""
4455
  "If a request matches any exclusion rule, it will not show on the traffic "
4456
  "viewer."
4457
  msgstr ""
4458
 
4459
+ #: src/features/traffic.php:515
4460
+ msgid "Custom Exclusions"
4461
+ msgstr ""
4462
+
4463
+ #: src/features/traffic.php:516
4464
+ msgid "Provide Custom Traffic Exclusions"
4465
+ msgstr ""
4466
+
4467
+ #: src/features/traffic.php:517
4468
+ msgid ""
4469
+ "For each entry, if the text is present in either the User Agent or request "
4470
+ "Path, it will be excluded."
4471
+ msgstr ""
4472
+
4473
+ #: src/features/traffic.php:518
4474
+ msgid "Take a new line for each entry."
4475
+ msgstr ""
4476
+
4477
+ #: src/features/traffic.php:519
4478
+ msgid "Comparisons are case-insensitive."
4479
+ msgstr ""
4480
+
4481
+ #: src/features/traffic.php:523
4482
  msgid "Auto Expiry Cleaning"
4483
  msgstr ""
4484
 
4485
+ #: src/features/traffic.php:524
4486
  msgid "Enable Traffic Log Auto Expiry"
4487
  msgstr ""
4488
 
4489
+ #: src/features/traffic.php:525
4490
  msgid "DB cleanup will delete logs older than this maximum value (in days)."
4491
  msgstr ""
4492
 
4493
+ #: src/features/traffic.php:529
4494
  msgid "Max Log Length"
4495
  msgstr ""
4496
 
4497
+ #: src/features/traffic.php:530
4498
  msgid "Maximum Traffic Log Length To Keep"
4499
  msgstr ""
4500
 
4501
+ #: src/features/traffic.php:531
4502
  msgid "DB cleanup will delete logs to maintain this maximum number of records."
4503
  msgstr ""
4504
 
4505
+ #: src/features/traffic.php:535
4506
  msgid "Auto Disable"
4507
  msgstr ""
4508
 
4509
+ #: src/features/traffic.php:536
4510
  msgid "Auto Disable Traffic Logging After 1 Week"
4511
  msgstr ""
4512
 
4513
+ #: src/features/traffic.php:539
4514
  #, php-format
4515
  msgid "Auto Disable At: %s"
4516
  msgstr ""
4517
 
4518
+ #: src/features/traffic.php:544
4519
  msgid "Turn on to prevent unnecessary long-term traffic logging."
4520
  msgstr ""
4521
 
4522
+ #: src/features/traffic.php:545
4523
  msgid "Timer resets after options save."
4524
  msgstr ""
4525
 
5066
  msgstr ""
5067
 
5068
  #: src/processors/autoupdates.php:540
5069
+ #: src/processors/loginprotect_backupcodes.php:181
5070
  #, php-format
5071
  msgid "Notice: %s"
5072
  msgstr ""
5171
  msgstr ""
5172
 
5173
  #: src/processors/base_wpsf.php:99 src/processors/base_wpsf.php:107
 
5174
  msgid "Whoops."
5175
  msgstr ""
5176
 
5260
  msgid "Firewall Trigger: %s."
5261
  msgstr ""
5262
 
5263
+ #: src/processors/firewall.php:160 src/processors/firewall.php:548
5264
  msgid "EXE File Uploads"
5265
  msgstr ""
5266
 
5308
  msgid "Firewall Block Response: %s."
5309
  msgstr ""
5310
 
5311
+ #: src/processors/firewall.php:475
5312
  #, php-format
5313
  msgid "%s has blocked a page visit to your site."
5314
  msgstr ""
5315
 
5316
+ #: src/processors/firewall.php:476
5317
  msgid "Log details for this visitor are below:"
5318
  msgstr ""
5319
 
5320
+ #: src/processors/firewall.php:481
5321
  #, php-format
5322
  msgid "You can look up the offending IP Address here: %s"
5323
  msgstr ""
5324
 
5325
+ #: src/processors/firewall.php:482
5326
  msgid "Firewall Block Alert"
5327
  msgstr ""
5328
 
5329
+ #: src/processors/firewall.php:536
5330
  msgid "Directory Traversal"
5331
  msgstr ""
5332
 
5333
+ #: src/processors/firewall.php:551
5334
  msgid "Leading Schema"
5335
  msgstr ""
5336
 
5337
+ #: src/processors/firewall.php:557
5338
  msgid "Aggressive Rules"
5339
  msgstr ""
5340
 
5341
+ #: src/processors/firewall.php:560
5342
  msgid "Unknown Rules"
5343
  msgstr ""
5344
 
5371
 
5372
  #: src/processors/hackprotect_corechecksumscan.php:265
5373
  #: src/processors/hackprotect_filecleanerscan.php:254
5374
+ #: src/processors/hackprotect_ptguard.php:495
5375
  #: src/processors/user_management.php:207
5376
  #: src/processors/user_management.php:235
5377
  msgid "Site URL"
5530
  msgid "Vulnerable Versions"
5531
  msgstr ""
5532
 
5533
+ #: src/processors/hackprotect_ptguard.php:178
5534
+ #, php-format
5535
+ msgid "File signatures removed for item \"%s\""
5536
+ msgstr ""
5537
+
5538
+ #: src/processors/hackprotect_ptguard.php:204
5539
+ #, php-format
5540
+ msgid "File signatures updated for item \"%s\""
5541
+ msgstr ""
5542
+
5543
+ #: src/processors/hackprotect_ptguard.php:449
5544
  msgid "Silenced repeated email alert from Plugin/Theme Scan Guard"
5545
  msgstr ""
5546
 
5547
+ #: src/processors/hackprotect_ptguard.php:491
5548
  #, php-format
5549
  msgid ""
5550
  "%s has detected at least 1 Plugins/Themes have been modified on your site."
5551
  msgstr ""
5552
 
5553
+ #: src/processors/hackprotect_ptguard.php:493
5554
  msgid ""
5555
  "You will receive only 1 email notification about these changes in a 1 week "
5556
  "period."
5557
  msgstr ""
5558
 
5559
+ #: src/processors/hackprotect_ptguard.php:497
5560
  msgid "Details of the problem items are below:"
5561
  msgstr ""
5562
 
5563
+ #: src/processors/hackprotect_ptguard.php:502
5564
  msgid "Modified Plugins:"
5565
  msgstr ""
5566
 
5567
+ #: src/processors/hackprotect_ptguard.php:510
5568
  msgid "Modified Themes:"
5569
  msgstr ""
5570
 
5571
+ #: src/processors/hackprotect_ptguard.php:520
5572
  msgid "Run the scanner"
5573
  msgstr ""
5574
 
5575
+ #: src/processors/hackprotect_ptguard.php:526
5576
  msgid "Plugins/Themes Have Been Altered"
5577
  msgstr ""
5578
 
5579
+ #: src/processors/hackprotect_ptguard.php:531
5580
  #, php-format
5581
  msgid "Successfully sent Plugin/Theme Guard email alert to: %s"
5582
  msgstr ""
5583
 
5584
+ #: src/processors/hackprotect_ptguard.php:534
5585
  #, php-format
5586
  msgid "Failed to send Plugin/Theme Guard email alert to: %s"
5587
  msgstr ""
5588
 
5589
+ #: src/processors/hackprotect_ptguard.php:689
5590
+ msgid "Plugin/Theme Guard"
5591
+ msgstr ""
5592
+
5593
  #: src/processors/hackprotect_wpvulnscan.php:112
5594
  msgid "Vulnerable"
5595
  msgstr ""
5736
  msgid "To turn this notice off, disable 2-Factor Authentication."
5737
  msgstr ""
5738
 
5739
+ #: src/processors/loginprotect_backupcodes.php:28
5740
+ msgid "Generate ONE-Time Backup 2FA Login Code"
5741
  msgstr ""
5742
 
5743
+ #: src/processors/loginprotect_backupcodes.php:29
5744
+ msgid "Delete Login Backup Code"
 
5745
  msgstr ""
5746
 
5747
+ #: src/processors/loginprotect_backupcodes.php:30
5748
  msgid ""
5749
+ "Backup login codes are not available if you do not have any other two-factor "
5750
+ "authentication modes active."
5751
  msgstr ""
5752
 
5753
+ #: src/processors/loginprotect_backupcodes.php:31
5754
+ msgid ""
5755
+ "Click to generate a backup login code for your two-factor authentication."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5756
  msgstr ""
5757
 
5758
+ #: src/processors/loginprotect_backupcodes.php:34
5759
+ msgid ""
5760
+ "This code will be displayed only once and you may use it to verify your "
5761
+ "login only once."
5762
  msgstr ""
5763
 
5764
+ #: src/processors/loginprotect_backupcodes.php:35
5765
+ msgid "Store it somewhere safe."
 
 
5766
  msgstr ""
5767
 
5768
+ #: src/processors/loginprotect_backupcodes.php:36
5769
+ msgid "Generating a new code will replace your existing code."
 
 
 
 
5770
  msgstr ""
5771
 
5772
+ #: src/processors/loginprotect_backupcodes.php:37
5773
  #: src/processors/loginprotect_googleauthenticator.php:38
5774
  msgid ""
5775
  "Use your Google Authenticator app to scan this QR code and enter the one "
5776
  "time password below."
5777
  msgstr ""
5778
 
5779
+ #: src/processors/loginprotect_backupcodes.php:38
5780
  #: src/processors/loginprotect_googleauthenticator.php:39
5781
  msgid ""
5782
  "If you have a problem with scanning the QR code enter this code manually "
5783
  "into the app."
5784
  msgstr ""
5785
 
5786
+ #: src/processors/loginprotect_backupcodes.php:39
5787
  #: src/processors/loginprotect_googleauthenticator.php:40
5788
  msgid "Check the box to remove Google Authenticator login authentication."
5789
  msgstr ""
5790
 
5791
+ #: src/processors/loginprotect_backupcodes.php:40
5792
  #: src/processors/loginprotect_googleauthenticator.php:41
5793
  #, php-format
5794
  msgid "Remove %s"
5795
  msgstr ""
5796
 
5797
+ #: src/processors/loginprotect_backupcodes.php:41
5798
+ msgid "Create Backup 2FA Login Code"
 
5799
  msgstr ""
5800
 
5801
+ #: src/processors/loginprotect_backupcodes.php:42
5802
  #: src/processors/loginprotect_googleauthenticator.php:43
5803
  msgid "Manual Code"
5804
  msgstr ""
5805
 
5806
+ #: src/processors/loginprotect_backupcodes.php:43
5807
  #: src/processors/loginprotect_googleauthenticator.php:44
5808
  msgid "Scan This QR Code"
5809
  msgstr ""
5810
 
5811
+ #: src/processors/loginprotect_backupcodes.php:44
5812
+ msgid "Backup Login Code"
5813
+ msgstr ""
5814
+
5815
+ #: src/processors/loginprotect_backupcodes.php:45
5816
  #: src/processors/loginprotect_googleauthenticator.php:46
5817
  #: src/processors/loginprotect_yubikey.php:46
5818
  #, php-format
5819
  msgid "Sorry, %s may not be added to another user's account."
5820
  msgstr ""
5821
 
5822
+ #: src/processors/loginprotect_backupcodes.php:46
5823
  #: src/processors/loginprotect_googleauthenticator.php:47
5824
  #: src/processors/loginprotect_yubikey.php:47
5825
  #, php-format
5828
  "Administrator."
5829
  msgstr ""
5830
 
5831
+ #: src/processors/loginprotect_backupcodes.php:46
5832
+ msgid "Backup Codes"
5833
+ msgstr ""
5834
+
5835
+ #: src/processors/loginprotect_backupcodes.php:47
5836
  #: src/processors/loginprotect_googleauthenticator.php:48
5837
  #: src/processors/loginprotect_twofactorauth.php:204
5838
  #: src/processors/loginprotect_yubikey.php:48
5840
  msgid "Provided by %s"
5841
  msgstr ""
5842
 
5843
+ #: src/processors/loginprotect_backupcodes.php:48
5844
  #: src/processors/loginprotect_googleauthenticator.php:49
5845
  #: src/processors/loginprotect_yubikey.php:49
5846
  msgid "Understand how to remove Google Authenticator"
5847
  msgstr ""
5848
 
5849
+ #: src/processors/loginprotect_backupcodes.php:75
5850
+ msgid "Please use your Backup Code to login."
5851
+ msgstr ""
5852
+
5853
+ #: src/processors/loginprotect_backupcodes.php:76
5854
+ msgid "Login Backup Code"
5855
+ msgstr ""
5856
+
5857
+ #: src/processors/loginprotect_backupcodes.php:133
5858
+ #: src/processors/loginprotect_googleauthenticator.php:288
5859
+ #: src/processors/loginprotect_twofactorauth.php:41
5860
+ #: src/processors/loginprotect_yubikey.php:239
5861
+ #, php-format
5862
+ msgid "User \"%s\" verified their identity using %s method."
5863
+ msgstr ""
5864
+
5865
+ #: src/processors/loginprotect_backupcodes.php:134
5866
+ #: src/processors/loginprotect_backupcodes.php:142
5867
+ msgid "Backup Code"
5868
+ msgstr ""
5869
+
5870
+ #: src/processors/loginprotect_backupcodes.php:141
5871
+ #: src/processors/loginprotect_googleauthenticator.php:296
5872
+ #: src/processors/loginprotect_twofactorauth.php:49
5873
+ #: src/processors/loginprotect_yubikey.php:247
5874
+ #, php-format
5875
+ msgid "User \"%s\" failed to verify their identity using %s method."
5876
+ msgstr ""
5877
+
5878
+ #: src/processors/loginprotect_backupcodes.php:169
5879
+ msgid ""
5880
+ "This is a quick notice to inform you that your Backup Login code was just "
5881
+ "used."
5882
+ msgstr ""
5883
+
5884
+ #: src/processors/loginprotect_backupcodes.php:170
5885
+ msgid "Your WordPress account had only 1 backup login code."
5886
+ msgstr ""
5887
+
5888
+ #: src/processors/loginprotect_backupcodes.php:171
5889
+ msgid ""
5890
+ "You must go to your profile and regenerate a new code if you want to use "
5891
+ "this method again."
5892
+ msgstr ""
5893
+
5894
+ #: src/processors/loginprotect_backupcodes.php:173
5895
+ #: src/processors/loginprotect_twofactorauth.php:159
5896
+ msgid "Login Details"
5897
+ msgstr ""
5898
+
5899
+ #: src/processors/loginprotect_backupcodes.php:174
5900
+ #: src/processors/loginprotect_twofactorauth.php:160
5901
+ msgid "URL"
5902
+ msgstr ""
5903
+
5904
+ #: src/processors/loginprotect_backupcodes.php:178
5905
+ msgid "Thank You."
5906
+ msgstr ""
5907
+
5908
+ #: src/processors/loginprotect_backupcodes.php:181
5909
+ msgid "Backup Login Code Just Used"
5910
+ msgstr ""
5911
+
5912
+ #: src/processors/loginprotect_cooldown.php:24
5913
+ msgid "Request Cooldown in effect."
5914
+ msgstr ""
5915
+
5916
+ #: src/processors/loginprotect_cooldown.php:26
5917
+ #, php-format
5918
+ msgid "You must wait %s seconds before attempting this action again."
5919
+ msgstr ""
5920
+
5921
+ #: src/processors/loginprotect_cooldown.php:31
5922
+ msgid ""
5923
+ "Cooldown triggered and request (login/register/lost-password) was blocked."
5924
+ msgstr ""
5925
+
5926
+ #: src/processors/loginprotect_gasp.php:29
5927
+ msgid "You MUST enable Javascript to be able to login"
5928
+ msgstr ""
5929
+
5930
+ #: src/processors/loginprotect_gasp.php:60
5931
+ #: src/processors/loginprotect_gasp.php:104
5932
+ #, php-format
5933
+ msgid "User \"%s\" attempted to %s but GASP checkbox was not present."
5934
+ msgstr ""
5935
+
5936
+ #: src/processors/loginprotect_gasp.php:62
5937
+ #: src/processors/loginprotect_gasp.php:71
5938
+ #: src/processors/loginprotect_gasp.php:106
5939
+ #: src/processors/loginprotect_gasp.php:115
5940
+ msgid "Probably a BOT."
5941
+ msgstr ""
5942
+
5943
+ #: src/processors/loginprotect_gasp.php:65
5944
+ #: src/processors/loginprotect_gasp.php:109
5945
+ msgid "You must check that box to say you're not a bot."
5946
+ msgstr ""
5947
+
5948
+ #: src/processors/loginprotect_gasp.php:69
5949
+ #: src/processors/loginprotect_gasp.php:113
5950
+ #, php-format
5951
+ msgid "User \"%s\" attempted to %s but they were caught by the GASP honeypot."
5952
+ msgstr ""
5953
+
5954
+ #: src/processors/loginprotect_gasp.php:74
5955
+ #: src/processors/loginprotect_gasp.php:118
5956
+ #, php-format
5957
+ msgid "You appear to be a bot - terminating %s attempt."
5958
+ msgstr ""
5959
+
5960
+ #: src/processors/loginprotect_googleauthenticator.php:36
5961
+ msgid "Provide the current code generated by your Google Authenticator app."
5962
+ msgstr ""
5963
+
5964
+ #: src/processors/loginprotect_googleauthenticator.php:37
5965
+ msgid "To reset this QR Code enter fake data here."
5966
+ msgstr ""
5967
+
5968
+ #: src/processors/loginprotect_googleauthenticator.php:42
5969
+ #: src/processors/loginprotect_googleauthenticator.php:206
5970
+ msgid "Google Authenticator Code"
5971
+ msgstr ""
5972
+
5973
  #: src/processors/loginprotect_googleauthenticator.php:107
5974
+ #: src/processors/loginprotect_googleauthenticator.php:152
5975
  msgid "Google Authenticator was successfully removed from the account."
5976
  msgstr ""
5977
 
5981
  "code is correct."
5982
  msgstr ""
5983
 
5984
+ #: src/processors/loginprotect_googleauthenticator.php:144
5985
  #: src/processors/loginprotect_yubikey.php:80
5986
  msgid "One Time Password (OTP) was not valid."
5987
  msgstr ""
5988
 
5989
+ #: src/processors/loginprotect_googleauthenticator.php:144
5990
  #: src/processors/loginprotect_yubikey.php:80
5991
  msgid "Please try again."
5992
  msgstr ""
5993
 
5994
+ #: src/processors/loginprotect_googleauthenticator.php:157
5995
  msgid ""
5996
  "An email has been sent to you in order to confirm Google Authenticator "
5997
  "removal"
5998
  msgstr ""
5999
 
6000
+ #: src/processors/loginprotect_googleauthenticator.php:161
6001
  msgid ""
6002
  "We tried to send an email for you to confirm Google Authenticator removal "
6003
  "but it failed."
6004
  msgstr ""
6005
 
6006
+ #: src/processors/loginprotect_googleauthenticator.php:183
6007
  #, php-format
6008
  msgid "%s was successfully added to your account."
6009
  msgstr ""
6010
 
6011
+ #: src/processors/loginprotect_googleauthenticator.php:205
 
 
 
 
 
 
 
 
 
 
 
 
6012
  msgid "Please use your Google Authenticator App to retrieve your code."
6013
  msgstr ""
6014
 
6015
+ #: src/processors/loginprotect_googleauthenticator.php:224
6016
  msgid ""
6017
  "You have requested the removal of Google Authenticator from your WordPress "
6018
  "account."
6019
  msgstr ""
6020
 
6021
+ #: src/processors/loginprotect_googleauthenticator.php:225
6022
  msgid "Please click the link below to confirm."
6023
  msgstr ""
6024
 
6025
+ #: src/processors/loginprotect_googleauthenticator.php:230
6026
  msgid "Google Authenticator Removal Confirmation"
6027
  msgstr ""
6028
 
6029
+ #: src/processors/loginprotect_googleauthenticator.php:254
6030
  msgid "Google Authenticator was successfully removed from this account."
6031
  msgstr ""
6032
 
6033
+ #: src/processors/loginprotect_intent.php:121
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6034
  msgid "Success"
6035
  msgstr ""
6036
 
6037
+ #: src/processors/loginprotect_intent.php:121
6038
  msgid "Thank you for authenticating your login."
6039
  msgstr ""
6040
 
6041
+ #: src/processors/loginprotect_intent.php:123
6042
+ msgid "If you used your Backup Code, you will need to reset it."
6043
+ msgstr ""
6044
+
6045
+ #: src/processors/loginprotect_intent.php:131
6046
  msgid "One or more of your authentication codes failed or was missing"
6047
  msgstr ""
6048
 
6049
+ #: src/processors/loginprotect_intent.php:269
6050
  msgid "Please supply all authentication codes"
6051
  msgstr ""
6052
 
6053
+ #: src/processors/loginprotect_intent.php:272
6054
  msgid "Please supply at least 1 authentication code"
6055
  msgstr ""
6056
 
6057
+ #: src/processors/loginprotect_intent.php:287
6058
  msgid "Cancel Login"
6059
  msgstr ""
6060
 
6061
+ #: src/processors/loginprotect_intent.php:288
6062
  msgid "Time Remaining"
6063
  msgstr ""
6064
 
6065
+ #: src/processors/loginprotect_intent.php:289
6066
  msgid "Calculating"
6067
  msgstr ""
6068
 
6069
+ #: src/processors/loginprotect_intent.php:290
6070
  msgid "Seconds"
6071
  msgstr ""
6072
 
6073
+ #: src/processors/loginprotect_intent.php:291
6074
  msgid "Login Expired"
6075
  msgstr ""
6076
 
6077
+ #: src/processors/loginprotect_intent.php:292
6078
  msgid "Verify My Login"
6079
  msgstr ""
6080
 
6081
+ #: src/processors/loginprotect_intent.php:294
6082
  msgid "What is this?"
6083
  msgstr ""
6084
 
6085
+ #: src/processors/loginprotect_intent.php:296
6086
  #, php-format
6087
  msgid "%s Login Verification"
6088
  msgstr ""
6089
 
6090
+ #: src/processors/loginprotect_intent.php:298
6091
  #, php-format
6092
  msgid "Don't ask again on this browser for %s."
6093
  msgstr ""
6094
 
6095
+ #: src/processors/loginprotect_intent.php:299
6096
  #, php-format
6097
  msgid "%s day"
6098
  msgid_plural "%s days"
6100
  msgstr[1] ""
6101
 
6102
  #: src/processors/loginprotect_twofactorauth.php:42
 
 
 
 
 
6103
  #: src/processors/loginprotect_twofactorauth.php:50
6104
+ msgid "Email Auth"
 
 
 
6105
  msgstr ""
6106
 
6107
  #: src/processors/loginprotect_twofactorauth.php:80
6125
  msgid "Verification Code: %s"
6126
  msgstr ""
6127
 
 
 
 
 
 
 
 
 
6128
  #: src/processors/loginprotect_twofactorauth.php:167
6129
  msgid "Why no login link?"
6130
  msgstr ""
6220
  msgstr ""
6221
 
6222
  #: src/processors/loginprotect_yubikey.php:44
6223
+ #: src/processors/loginprotect_yubikey.php:240
6224
+ #: src/processors/loginprotect_yubikey.php:248
6225
+ #: src/processors/loginprotect_yubikey.php:266
6226
  msgid "Yubikey OTP"
6227
  msgstr ""
6228
 
6253
  msgid "No changes were made to your Yubikey configuration"
6254
  msgstr ""
6255
 
6256
+ #: src/processors/loginprotect_yubikey.php:264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6257
  msgid "Use your Yubikey to generate a new code."
6258
  msgstr ""
6259
 
6260
+ #: src/processors/loginprotect_yubikey.php:341
6261
  #, php-format
6262
  msgid ""
6263
  "User \"%s\" logged in without a Yubikey One Time Password because no "
6264
  "username-yubikey pair was found for this user."
6265
  msgstr ""
6266
 
6267
+ #: src/processors/loginprotect_yubikey.php:348
6268
  #, php-format
6269
  msgid ""
6270
  "User \"%s\" attempted to login but Yubikey ID \"%s\" used was not in list of "
6271
  "authorised keys."
6272
  msgstr ""
6273
 
6274
+ #: src/processors/loginprotect_yubikey.php:354
6275
+ #: src/processors/loginprotect_yubikey.php:372
6276
  #, php-format
6277
  msgid "ERROR: %s"
6278
  msgstr ""
6279
 
6280
+ #: src/processors/loginprotect_yubikey.php:354
6281
  msgid ""
6282
  "The Yubikey provided is not on the list of permitted keys for this user."
6283
  msgstr ""
6284
 
6285
+ #: src/processors/loginprotect_yubikey.php:361
6286
+ #, php-format
6287
+ msgid ""
6288
+ "User \"%s\" successfully logged in using a validated Yubikey One Time "
6289
+ "Password."
6290
+ msgstr ""
6291
+
6292
+ #: src/processors/loginprotect_yubikey.php:367
6293
  #, php-format
6294
  msgid ""
6295
  "User \"%s\" attempted to login but Yubikey One Time Password failed to "
6296
  "validate due to invalid Yubi API response.\"."
6297
  msgstr ""
6298
 
6299
+ #: src/processors/loginprotect_yubikey.php:372
6300
  msgid "The Yubikey authentication was not validated successfully."
6301
  msgstr ""
6302
 
6644
  msgid "Invalid email address"
6645
  msgstr ""
6646
 
6647
+ #: src/wizards/login_protect.php:69
6648
+ msgid "Verification email sent (please check your email including your SPAM)."
6649
+ msgstr ""
6650
+
6651
+ #: src/wizards/login_protect.php:70
6652
+ msgid ""
6653
+ "Enter the code from the email into the form above and click the button to "
6654
+ "verify."
6655
+ msgstr ""
6656
+
6657
+ #: src/wizards/login_protect.php:119
6658
  msgid "Code was empty."
6659
  msgstr ""
6660
 
6661
+ #: src/wizards/login_protect.php:146
6662
  msgid "Google Authenticator was enabled for the site."
6663
  msgstr ""
6664
 
6665
+ #: src/wizards/login_protect.php:161
6666
  #, php-format
6667
  msgid "Multi-Factor Authentication was %s for the site."
6668
  msgstr ""
6669
 
6670
+ #: src/wizards/login_protect.php:162
6671
  msgid "enabled"
6672
  msgstr ""
6673
 
6674
+ #: src/wizards/login_protect.php:162
6675
  msgid "disabled"
6676
  msgstr ""
6677
 
languages/wp-simple-firewall-pt_BR.mo CHANGED
Binary file
plugin-spec.php CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "properties": {
3
- "version": "6.9.4",
4
- "release_timestamp": 1536825761,
5
  "slug_parent": "icwp",
6
  "slug_plugin": "wpsf",
7
  "human_name": "Shield",
@@ -12,7 +12,7 @@
12
  "logging_enabled": true,
13
  "show_dashboard_widget": true,
14
  "autoupdate": "confidence",
15
- "autoupdate_days": 3,
16
  "options_encoding": "json",
17
  "enable_premium": true
18
  },
@@ -30,24 +30,24 @@
30
  "includes": {
31
  "admin": {
32
  "css": [
33
- "global-plugin",
34
- "featherlight"
35
  ],
36
  "js": [
37
  "jquery",
38
- "global-plugin",
39
- "featherlight"
40
  ]
41
  },
42
  "plugin_admin": {
43
  "css": [
44
  "bootstrap4",
45
- "plugin"
 
46
  ],
47
  "js": [
48
  "bootstrap4.bundle.min",
49
  "jquery",
50
- "plugin"
 
51
  ]
52
  },
53
  "frontend": {
1
  {
2
  "properties": {
3
+ "version": "6.10.0",
4
+ "release_timestamp": 1539604800,
5
  "slug_parent": "icwp",
6
  "slug_plugin": "wpsf",
7
  "human_name": "Shield",
12
  "logging_enabled": true,
13
  "show_dashboard_widget": true,
14
  "autoupdate": "confidence",
15
+ "autoupdate_days": 2,
16
  "options_encoding": "json",
17
  "enable_premium": true
18
  },
30
  "includes": {
31
  "admin": {
32
  "css": [
33
+ "global-plugin"
 
34
  ],
35
  "js": [
36
  "jquery",
37
+ "global-plugin"
 
38
  ]
39
  },
40
  "plugin_admin": {
41
  "css": [
42
  "bootstrap4",
43
+ "plugin",
44
+ "featherlight"
45
  ],
46
  "js": [
47
  "bootstrap4.bundle.min",
48
  "jquery",
49
+ "plugin",
50
+ "featherlight"
51
  ]
52
  },
53
  "frontend": {
readme.txt CHANGED
@@ -8,7 +8,7 @@ Requires at least: 3.5.0
8
  Requires PHP: 5.2.4
9
  Recommended PHP: 5.4
10
  Tested up to: 4.9
11
- Stable tag: 6.9.4
12
 
13
  Complete All-In-One Protection for your WordPress sites, that makes Security Easy for Everyone - it doesn't have to be hard anymore.
14
 
@@ -345,6 +345,8 @@ Possible options are: network_admin, administrator, editor, author, contributor,
345
 
346
  == Changelog ==
347
 
 
 
348
  Shield Pro brings exclusive features to the serious webmaster to maximise site security.
349
  You'll also have access to our email technical support team.
350
 
@@ -352,43 +354,23 @@ You will always be able to use Shield Security and its free features in-full.
352
 
353
  [Go Pro for just $1/month](https://icwp.io/aa).
354
 
355
- = 6.9.4 - Current Release =
356
- *Released: 13th September, 2018*
357
-
358
- * **(v.4)** FIXED: Bug where 2FA by email user roles get reset in some cases.
359
- * **(v.3)** ADDED: Support for AppleBot in the [Traffic Watcher](https://icwp.io/dc).
360
- * **(v.3)** FIXED: [Plugin/Theme Guard](https://icwp.io/bq) bug not capturing updates correctly.
361
- * **(v.3)** FIXED: Google Authenticator could not be removed from profile.
362
-
363
- = 6.9.0 - Series =
364
- *Released: 6th September, 2018* - [Release Notes](https://icwp.io/dc)
365
-
366
- * **(v.2)** FIXED: Prevent crashing on sites with PHP < v5.4
367
- * **(v.1)** ADDED: Support for Yandex search engine in the [Traffic Watcher](https://icwp.io/dc).
368
- * **(v.1)** IMPROVED: WooCommerce checkout handling with reCAPTCHA.
369
- * **(v.0)** NEW: [**PRO**] [Traffic Watcher](https://icwp.io/dc) - live tracking of all requests to your site.
370
- * **(v.0)** NEW: [**PRO**] [Yubikey](https://icwp.io/dc) - Allows for multiple Yubikeys on the same user profile.
371
- * **(v.0)** ADDED: [**PRO**] Option to include listing of affected files within Hack Guard notification emails.
372
- * **(v.0)** ADDED: Option to delete the Security Admin Access Key
373
- * **(v.0)** ADDED: Option to add WooCommerce roles to 2FA-Email setting.
374
- * **(v.0)** CHANGED: Basic Stats system now requires minimum PHP v5.4.
375
- * **(v.0)** CHANGED: Password Policies now requires minimum WordPress v4.4.
376
- * **(v.0)** IMPROVED: Password expiration now redirects to the 'set password' screen, instead of the user profile.
377
- * **(v.0)** IMPROVED: Password capture for purposes of password policies is improved.
378
- * **(v.0)** IMPROVED: You can now delete the 'forceoff' file from inside the WP Admin.
379
- * **(v.0)** IMPROVED: Audit Trail entries for emails will identify the file that's calling the `wp_mail` function.
380
- * **(v.0)** IMPROVED: Audit Trail entries for post editing will identify the post type wherever possible.
381
- * **(v.0)** IMPROVED: Audit Trail entries will try to display all message text correctly.
382
- * **(v.0)** IMPROVED: Login/Register/Password forms are only checked when visitor is not logged-in.
383
- * **(v.0)** IMPROVED: Major database code refactoring and other code improvements.
384
- * **(v.0)** IMPROVED: User sessions handling.
385
- * **(v.0)** IMPROVED: Security Admin UX - ajax session checking, with admin notifications and auto-page reload.
386
- * **(v.0)** IMPROVED: Security Admin password setting now requires a confirmation password entry.
387
- * **(v.0)** IMPROVED: Refined Cooldown timing system.
388
- * **(v.0)** IMPROVED: Refined Bot checkbox Javascript.
389
- * **(v.0)** IMPROVED: Cron entry cleanup after deactivation.
390
- * **(v.0)** UPDATED: Bootstrap libraries to latest release v4.1.3.
391
- * **(v.0)** FIXED: Potential bug with Plugin/Themes guard scanning.
392
- * **(v.0)** FIXED: PHP Warning(s).
393
 
394
  #### [Full Changelog](https://ps.w.org/wp-simple-firewall/trunk/changelog.html)
8
  Requires PHP: 5.2.4
9
  Recommended PHP: 5.4
10
  Tested up to: 4.9
11
+ Stable tag: 6.10.0
12
 
13
  Complete All-In-One Protection for your WordPress sites, that makes Security Easy for Everyone - it doesn't have to be hard anymore.
14
 
345
 
346
  == Changelog ==
347
 
348
+ ** IMPORTANT ** : Shield Security v7+ will support only [PHP versions 5.4 and above](https://icwp.io/dh).
349
+
350
  Shield Pro brings exclusive features to the serious webmaster to maximise site security.
351
  You'll also have access to our email technical support team.
352
 
354
 
355
  [Go Pro for just $1/month](https://icwp.io/aa).
356
 
357
+ = 6.10.0 - Current Release =
358
+ *Released: 15th October, 2018* - [Release Notes](https://icwp.io/dg)
359
+
360
+ = 6.10 - Series =
361
+ *Released: 15th October, 2018* - [Release Notes](https://icwp.io/dg)
362
+
363
+ * **(v.0)** NEW: [**PRO**] 2FA Login Backup Codes - all users can create a backup login code in-case their MFA factors are temporarily unavailable.
364
+ * **(v.0)** NEW: [**PRO**] White Label - you can now specify custom image for 2FA login screen.
365
+ * **(v.0)** ADDED: [**PRO**] Custom Exclusion Rules for Traffic Watcher so you can exclude certain User Agents and request paths.
366
+ * **(v.0)** ADDED: Detection of official spiders/bots for Google, Bing, Apple and Yandex - these visitors will never get blacklisted.
367
+ * **(v.0)** IMPROVED: Two-Factor Authentication system much improved (+ critical bug fix).
368
+ * **(v.0)** IMPROVED: Audit Trail entries for 2FA login factors.
369
+ * **(v.0)** IMPROVED: Fixes for Two-Factor Authentication wizard UX.
370
+ * **(v.0)** IMPROVED: Traffic Watcher now honours the IP Whitelist.
371
+ * **(v.0)** IMPROVED: Security Admin restriction for creating/editing/deleting Administrator users is much improved.
372
+ * **(v.0)** IMPROVED: All Shield cookies are SSL-only by default for HTTPS sites.
373
+ * **(v.0)** FIXED: GASP checkbox Javascript breaking in a particular scenario.
374
+ * **(v.0)** ADDED: Optional plugin deactivation survey.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
 
376
  #### [Full Changelog](https://ps.w.org/wp-simple-firewall/trunk/changelog.html)
resources/css/global-plugin.css CHANGED
@@ -28,6 +28,12 @@
28
  color: rgb(103, 21, 0);
29
  text-align: right;
30
  }
 
 
 
 
 
 
31
  .notice-icon {
32
  display: none;
33
  float: left;
28
  color: rgb(103, 21, 0);
29
  text-align: right;
30
  }
31
+
32
+ .plugin_update_message {
33
+ color: #dd3333;
34
+ font-weight: bolder;
35
+ }
36
+
37
  .notice-icon {
38
  display: none;
39
  float: left;
resources/css/plugin.css CHANGED
@@ -660,7 +660,7 @@ input:checked + .icwp-slider:before {
660
  min-width: 760px; /** prevents col breaking **/
661
  }
662
  #TopPluginIcon {
663
- background: url("../images/shield/SHIELDSECURITY.png?ver=2.0") no-repeat 0 0 #f1f1f1;
664
  border-bottom: 1px solid #ccc;
665
 
666
  height: 128px;
660
  min-width: 760px; /** prevents col breaking **/
661
  }
662
  #TopPluginIcon {
663
+ background: url("../images/pluginlogo_128x128.png?ver=2.0") no-repeat 0 0 #f1f1f1;
664
  border-bottom: 1px solid #ccc;
665
 
666
  height: 128px;
resources/images/pluginlogo_banner-772x250.png ADDED
Binary file
resources/images/shield/SHIELDSECURITY.png DELETED
Binary file
resources/js/global-plugin.js CHANGED
@@ -28,114 +28,162 @@ var iCWP_WPSF_SecurityAdmin = new function () {
28
  };
29
  }();
30
 
31
- var iCWP_WPSF_HackGuard_Reinstall = new function () {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
- var sActiveFile;
34
- var bActivate;
 
 
 
 
 
35
 
36
- this.initialise = function () {
37
- jQuery( document ).ready( function () {
 
 
 
 
 
38
 
39
- var $oTr;
40
- jQuery( 'table.wp-list-table.plugins > tbody > tr' ).each( function ( nIndex ) {
41
- $oTr = jQuery( this );
42
- if ( $oTr.data( 'plugin' ) !== undefined
43
- && icwp_wpsf_vars_hp.reinstallable.indexOf( $oTr.data( 'plugin' ) ) >= 0 ) {
44
- $oTr.addClass( 'reinstallable' );
45
- }
46
- } );
47
 
48
- jQuery( document ).on( "click", 'tr.reinstallable .row-actions .icwp-reinstall a', promptReinstall );
49
- jQuery( document ).on( "click", 'tr.reinstallable .row-actions .activate a', promptActivate );
50
-
51
- var oShareSettings = {
52
- title: 'Re-Install Plugin',
53
- dialogClass: 'wp-dialog',
54
- autoOpen: false,
55
- draggable: false,
56
- width: 'auto',
57
- modal: true,
58
- resizable: false,
59
- closeOnEscape: true,
60
- position: {
61
- my: "center",
62
- at: "center",
63
- of: window
64
- },
65
- open: function () {
66
- // close dialog by clicking the overlay behind it
67
- jQuery( '.ui-widget-overlay' ).bind( 'click', function () {
68
- jQuery( this ).dialog( 'close' );
69
- } )
70
- },
71
- create: function () {
72
- // style fix for WordPress admin
73
- jQuery( '.ui-dialog-titlebar-close' ).addClass( 'ui-button' );
74
- }
75
- };
76
-
77
- var $oReinstallDialog = jQuery( '#icwpWpsfReinstall' );
78
- oShareSettings[ 'buttons' ] = {
79
- "Okay, Re-Install It": function () {
80
- jQuery( this ).dialog( "close" );
81
- reinstall_plugin( 1 );
82
- },
83
- "Cancel": function () {
84
- jQuery( this ).dialog( "close" );
85
- }
86
- };
87
- $oReinstallDialog.dialog( oShareSettings );
88
-
89
- var $oActivateReinstallDialog = jQuery( '#icwpWpsfActivateReinstall' );
90
- oShareSettings[ 'buttons' ] = {
91
- "Re-Install First, Then Activate": function () {
92
- jQuery( this ).dialog( "close" );
93
- reinstall_plugin( 1 );
94
- },
95
- "Activate Only": function () {
96
- jQuery( this ).dialog( "close" );
97
- reinstall_plugin( 0 );
98
  }
99
- };
100
- $oActivateReinstallDialog.dialog( oShareSettings );
101
- } );
102
- };
103
 
104
- var promptReinstall = function ( event ) {
105
- event.preventDefault();
106
- bActivate = 0;
107
- sActiveFile = jQuery( event.target ).closest( 'tr' ).data( 'plugin' );
108
- jQuery( '#icwpWpsfReinstall' ).dialog( 'open' );
109
- return false;
110
- };
 
 
 
 
 
 
 
111
 
112
- var promptActivate = function ( event ) {
113
- event.preventDefault();
114
- bActivate = 1;
115
- sActiveFile = jQuery( event.target ).closest( 'tr' ).data( 'plugin' );
116
- jQuery( '#icwpWpsfActivateReinstall' ).dialog( 'open' );
117
- return false;
118
- };
119
 
120
- var reinstall_plugin = function ( bReinstall ) {
121
- iCWP_WPSF_BodyOverlay.show();
 
 
 
 
 
 
122
 
123
- var $aData = icwp_wpsf_vars_hp.ajax_reinstall;
124
- $aData[ 'file' ] = sActiveFile;
125
- $aData[ 'reinstall' ] = bReinstall;
126
- $aData[ 'activate' ] = bActivate;
127
 
128
- jQuery.post( ajaxurl, $aData, function ( oResponse ) {
 
 
129
 
130
- } ).always( function () {
131
- location.reload( true );
132
- bActivate = null;
133
- }
134
- );
 
 
 
135
 
136
- return false;
137
- };
138
- }();
 
 
139
 
140
  /** TODO: THIS AJAX IS NOT COMPLETE **/
141
  var iCWP_WPSF_Autoupdates = new function () {
@@ -195,7 +243,7 @@ var iCWP_WPSF_Growl = new function () {
195
  }, 380 );
196
  setTimeout( function () {
197
  $oDiv.css( 'width', 0 );
198
-
199
  setTimeout( function () {
200
  $oDiv.html( '' )
201
  .fadeOut();
@@ -239,7 +287,82 @@ var iCWP_WPSF_BodyOverlay = new function () {
239
  iCWP_WPSF_BodyOverlay.initialise();
240
  iCWP_WPSF_SecurityAdmin.initialise();
241
 
242
- /** only run when HackGuard module is processing enqueues **/
243
- if ( typeof icwp_wpsf_vars_hp !== 'undefined' ) {
244
- iCWP_WPSF_HackGuard_Reinstall.initialise();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  }
28
  };
29
  }();
30
 
31
+ /** only run when HackGuard module is processing enqueues **/
32
+ if ( typeof icwp_wpsf_vars_hp !== 'undefined' ) {
33
+ var iCWP_WPSF_HackGuard_Reinstall = new function () {
34
+
35
+ var sActiveFile;
36
+ var bActivate;
37
+
38
+ this.initialise = function () {
39
+ jQuery( document ).ready( function () {
40
+
41
+ var $oTr;
42
+ jQuery( 'table.wp-list-table.plugins > tbody > tr' ).each( function ( nIndex ) {
43
+ $oTr = jQuery( this );
44
+ if ( $oTr.data( 'plugin' ) !== undefined
45
+ && icwp_wpsf_vars_hp.reinstallable.indexOf( $oTr.data( 'plugin' ) ) >= 0 ) {
46
+ $oTr.addClass( 'reinstallable' );
47
+ }
48
+ } );
49
+
50
+ jQuery( document ).on( "click", 'tr.reinstallable .row-actions .icwp-reinstall a', promptReinstall );
51
+ jQuery( document ).on( "click", 'tr.reinstallable .row-actions .activate a', promptActivate );
52
+
53
+ var oShareSettings = {
54
+ title: 'Re-Install Plugin',
55
+ dialogClass: 'wp-dialog',
56
+ autoOpen: false,
57
+ draggable: false,
58
+ width: 'auto',
59
+ modal: true,
60
+ resizable: false,
61
+ closeOnEscape: true,
62
+ position: {
63
+ my: "center",
64
+ at: "center",
65
+ of: window
66
+ },
67
+ open: function () {
68
+ // close dialog by clicking the overlay behind it
69
+ jQuery( '.ui-widget-overlay' ).bind( 'click', function () {
70
+ jQuery( this ).dialog( 'close' );
71
+ } )
72
+ },
73
+ create: function () {
74
+ // style fix for WordPress admin
75
+ jQuery( '.ui-dialog-titlebar-close' ).addClass( 'ui-button' );
76
+ }
77
+ };
78
+
79
+ var $oReinstallDialog = jQuery( '#icwpWpsfReinstall' );
80
+ oShareSettings[ 'buttons' ] = {
81
+ "Okay, Re-Install It": function () {
82
+ jQuery( this ).dialog( "close" );
83
+ reinstall_plugin( 1 );
84
+ },
85
+ "Cancel": function () {
86
+ jQuery( this ).dialog( "close" );
87
+ }
88
+ };
89
+ $oReinstallDialog.dialog( oShareSettings );
90
+
91
+ var $oActivateReinstallDialog = jQuery( '#icwpWpsfActivateReinstall' );
92
+ oShareSettings[ 'buttons' ] = {
93
+ "Re-Install First, Then Activate": function () {
94
+ jQuery( this ).dialog( "close" );
95
+ reinstall_plugin( 1 );
96
+ },
97
+ "Activate Only": function () {
98
+ jQuery( this ).dialog( "close" );
99
+ reinstall_plugin( 0 );
100
+ }
101
+ };
102
+ $oActivateReinstallDialog.dialog( oShareSettings );
103
+ } );
104
+ };
105
 
106
+ var promptReinstall = function ( event ) {
107
+ event.preventDefault();
108
+ bActivate = 0;
109
+ sActiveFile = jQuery( event.target ).closest( 'tr' ).data( 'plugin' );
110
+ jQuery( '#icwpWpsfReinstall' ).dialog( 'open' );
111
+ return false;
112
+ };
113
 
114
+ var promptActivate = function ( event ) {
115
+ event.preventDefault();
116
+ bActivate = 1;
117
+ sActiveFile = jQuery( event.target ).closest( 'tr' ).data( 'plugin' );
118
+ jQuery( '#icwpWpsfActivateReinstall' ).dialog( 'open' );
119
+ return false;
120
+ };
121
 
122
+ var reinstall_plugin = function ( bReinstall ) {
123
+ iCWP_WPSF_BodyOverlay.show();
 
 
 
 
 
 
124
 
125
+ var $aData = icwp_wpsf_vars_hp.ajax_reinstall;
126
+ $aData[ 'file' ] = sActiveFile;
127
+ $aData[ 'reinstall' ] = bReinstall;
128
+ $aData[ 'activate' ] = bActivate;
129
+
130
+ jQuery.post( ajaxurl, $aData, function ( oResponse ) {
131
+
132
+ } ).always( function () {
133
+ location.reload( true );
134
+ bActivate = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  }
136
+ );
 
 
 
137
 
138
+ return false;
139
+ };
140
+ }();
141
+ iCWP_WPSF_HackGuard_Reinstall.initialise();
142
+ }
143
+
144
+ if ( typeof icwp_wpsf_vars_lg !== 'undefined' ) {
145
+ var iCWP_WPSF_LoginGuard_BackupCodes = new function () {
146
+ this.initialise = function () {
147
+ jQuery( document ).ready( function () {
148
+ jQuery( document ).on( "click", "a#IcwpWpsfGenBackupLoginCode", genBackupCode );
149
+ jQuery( document ).on( "click", "a#IcwpWpsfDelBackupLoginCode", deleteBackupCode );
150
+ } );
151
+ };
152
 
153
+ var genBackupCode = function ( event ) {
154
+ event.preventDefault();
155
+ iCWP_WPSF_BodyOverlay.show();
 
 
 
 
156
 
157
+ jQuery.post( ajaxurl, icwp_wpsf_vars_lg.ajax_gen_backup_codes,
158
+ function ( oResponse ) {
159
+ alert( 'Your login backup code: ' + oResponse.data.code );
160
+ }
161
+ ).always( function () {
162
+ location.reload( true );
163
+ }
164
+ );
165
 
166
+ return false;
167
+ };
 
 
168
 
169
+ var deleteBackupCode = function ( event ) {
170
+ event.preventDefault();
171
+ iCWP_WPSF_BodyOverlay.show();
172
 
173
+ jQuery.post( ajaxurl, icwp_wpsf_vars_lg.ajax_del_backup_codes,
174
+ function ( oResponse ) {
175
+ }
176
+ ).always( function () {
177
+ location.reload( true );
178
+ // iCWP_WPSF_BodyOverlay.hide();
179
+ }
180
+ );
181
 
182
+ return false;
183
+ };
184
+ }();
185
+ iCWP_WPSF_LoginGuard_BackupCodes.initialise();
186
+ }
187
 
188
  /** TODO: THIS AJAX IS NOT COMPLETE **/
189
  var iCWP_WPSF_Autoupdates = new function () {
243
  }, 380 );
244
  setTimeout( function () {
245
  $oDiv.css( 'width', 0 );
246
+
247
  setTimeout( function () {
248
  $oDiv.html( '' )
249
  .fadeOut();
287
  iCWP_WPSF_BodyOverlay.initialise();
288
  iCWP_WPSF_SecurityAdmin.initialise();
289
 
290
+ if ( typeof icwp_wpsf_vars_plugin !== 'undefined' ) {
291
+
292
+ var iCWP_WPSF_Plugin_Deactivate_Survey = new function () {
293
+
294
+ this.initialise = function () {
295
+ jQuery( document ).ready( function () {
296
+
297
+ jQuery( document ).on( "click",
298
+ '[data-plugin="' + icwp_wpsf_vars_plugin.file + '"] span.deactivate a',
299
+ promptSurvey
300
+ );
301
+
302
+ var oShareSettings = {
303
+ title: 'Care To Share?',
304
+ dialogClass: 'wp-dialog',
305
+ autoOpen: false,
306
+ draggable: false,
307
+ width: 'auto',
308
+ modal: true,
309
+ resizable: false,
310
+ closeOnEscape: true,
311
+ position: {
312
+ my: "center",
313
+ at: "center",
314
+ of: window
315
+ },
316
+ open: function () {
317
+ // close dialog by clicking the overlay behind it
318
+ jQuery( '.ui-widget-overlay' ).bind( 'click', function () {
319
+ jQuery( this ).dialog( 'close' );
320
+ } )
321
+ },
322
+ create: function () {
323
+ // style fix for WordPress admin
324
+ jQuery( '.ui-dialog-titlebar-close' ).addClass( 'ui-button' );
325
+ },
326
+ close: function () {
327
+ window.location.href = icwp_wpsf_vars_plugin.hrefs.deactivate;
328
+ }
329
+ };
330
+
331
+ var $oSurveyDialog = jQuery( '#icwpWpsfSurvey' );
332
+ oShareSettings[ 'buttons' ] = {
333
+ "Close (I don't want to help)": function () {
334
+ jQuery( this ).dialog( "close" );
335
+ },
336
+ "Yes (Send my feedback)": function () {
337
+ send_survey_deactivate();
338
+ jQuery( this ).dialog( "close" );
339
+ }
340
+ };
341
+ $oSurveyDialog.dialog( oShareSettings );
342
+ } );
343
+ };
344
+
345
+ var promptSurvey = function ( event ) {
346
+ event.preventDefault();
347
+ iCWP_WPSF_BodyOverlay.show();
348
+ jQuery( '#icwpWpsfSurvey' ).dialog( 'open' );
349
+ return false;
350
+ };
351
+
352
+ var send_survey_deactivate = function () {
353
+
354
+ var $aData = icwp_wpsf_vars_plugin.ajax.send_deactivate_survey;
355
+ jQuery.each( jQuery( '#icwpWpsfSurveyForm' ).serializeArray(),
356
+ function ( _, kv ) {
357
+ $aData[ kv.name ] = kv.value;
358
+ }
359
+ );
360
+
361
+ jQuery.post( ajaxurl, $aData );
362
+ setTimeout( function () {}, 2000 ); // give the request time to complete
363
+
364
+ return false;
365
+ };
366
+ }();
367
+ iCWP_WPSF_Plugin_Deactivate_Survey.initialise();
368
  }
src/common/easydigitaldownloads/ICWP_EDD_LicenseVO.php CHANGED
@@ -191,10 +191,12 @@ class ICWP_EDD_LicenseVO {
191
  }
192
 
193
  /**
 
194
  * @return $this
195
  */
196
- public function updateLastVerifiedAt() {
197
- return $this->setRawKey( 'last_verified_at', $this->getLastRequestAt() );
 
198
  }
199
 
200
  /**
191
  }
192
 
193
  /**
194
+ * @param bool $bAddRandom
195
  * @return $this
196
  */
197
+ public function updateLastVerifiedAt( $bAddRandom = false ) {
198
+ $nRandom = $bAddRandom ? rand( -12, 12 )*HOUR_IN_SECONDS : 0;
199
+ return $this->setRawKey( 'last_verified_at', $this->getLastRequestAt() + $nRandom );
200
  }
201
 
202
  /**
src/common/icwp-data.php CHANGED
@@ -48,6 +48,16 @@ class ICWP_WPSF_DataProcessor extends ICWP_WPSF_Foundation {
48
  return self::$nRequestTime;
49
  }
50
 
 
 
 
 
 
 
 
 
 
 
51
  /**
52
  * @param array $aArray1
53
  * @param array $aArray2
@@ -260,10 +270,20 @@ class ICWP_WPSF_DataProcessor extends ICWP_WPSF_Foundation {
260
 
261
  /**
262
  * @param string $sUrl
 
263
  * @return bool
264
  */
265
- public function validUrl( $sUrl ) {
266
- return filter_var( $sUrl, FILTER_VALIDATE_URL );
 
 
 
 
 
 
 
 
 
267
  }
268
 
269
  /**
@@ -550,7 +570,7 @@ class ICWP_WPSF_DataProcessor extends ICWP_WPSF_Foundation {
550
  * @param bool $bSsl
551
  * @return bool
552
  */
553
- public function setCookie( $sKey, $mValue, $nExpireLength = 3600, $sPath = null, $sDomain = null, $bSsl = false ) {
554
  $_COOKIE[ $sKey ] = $mValue;
555
  if ( function_exists( 'headers_sent' ) && headers_sent() ) {
556
  return false;
@@ -561,7 +581,7 @@ class ICWP_WPSF_DataProcessor extends ICWP_WPSF_Foundation {
561
  (int)( $this->time() + $nExpireLength ),
562
  ( is_null( $sPath ) && defined( 'COOKIEPATH' ) ) ? COOKIEPATH : $sPath,
563
  ( is_null( $sDomain ) && defined( 'COOKIE_DOMAIN' ) ) ? COOKIE_DOMAIN : $sDomain,
564
- $bSsl
565
  );
566
  }
567
 
48
  return self::$nRequestTime;
49
  }
50
 
51
+ /**
52
+ * @param array $aA
53
+ * @return array
54
+ */
55
+ public function shuffleArray( $aA ) {
56
+ $aKeys = array_keys( $aA );
57
+ shuffle( $aKeys );
58
+ return array_merge( array_flip( $aKeys ), $aA );
59
+ }
60
+
61
  /**
62
  * @param array $aArray1
63
  * @param array $aArray2
270
 
271
  /**
272
  * @param string $sUrl
273
+ * @param bool $bVerify
274
  * @return bool
275
  */
276
+ public function isValidUrl( $sUrl, $bVerify = false ) {
277
+ $bValid = filter_var( $sUrl, FILTER_VALIDATE_URL );
278
+ if ( $bValid && $bVerify ) {
279
+ $mRes = $this->loadFS()->getUrl( $sUrl );
280
+ if ( is_array( $mRes ) && isset( $mRes[ 'http_response' ] ) ) {
281
+ /** @var WP_HTTP_Requests_Response $oResp */
282
+ $oResp = $mRes[ 'http_response' ];
283
+ $bValid = $oResp->get_status() >= 200 && $oResp->get_status() < 300;
284
+ }
285
+ }
286
+ return $bValid;
287
  }
288
 
289
  /**
570
  * @param bool $bSsl
571
  * @return bool
572
  */
573
+ public function setCookie( $sKey, $mValue, $nExpireLength = 3600, $sPath = null, $sDomain = null, $bSsl = true ) {
574
  $_COOKIE[ $sKey ] = $mValue;
575
  if ( function_exists( 'headers_sent' ) && headers_sent() ) {
576
  return false;
581
  (int)( $this->time() + $nExpireLength ),
582
  ( is_null( $sPath ) && defined( 'COOKIEPATH' ) ) ? COOKIEPATH : $sPath,
583
  ( is_null( $sDomain ) && defined( 'COOKIE_DOMAIN' ) ) ? COOKIE_DOMAIN : $sDomain,
584
+ $bSsl && is_ssl()
585
  );
586
  }
587
 
src/common/icwp-foundation.php CHANGED
@@ -5,11 +5,21 @@ if ( class_exists( 'ICWP_WPSF_Foundation', false ) ) {
5
 
6
  class ICWP_WPSF_Foundation {
7
 
 
 
8
  /**
9
  * @var array
10
  */
11
  private static $aDic;
12
 
 
 
 
 
 
 
 
 
13
  /**
14
  * @return ICWP_WPSF_DataProcessor
15
  */
@@ -125,6 +135,18 @@ class ICWP_WPSF_Foundation {
125
  return self::getService( $sKey );
126
  }
127
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  /**
129
  * @return ICWP_WPSF_Ssl
130
  */
@@ -293,7 +315,7 @@ class ICWP_WPSF_Foundation {
293
  * @param string $sFile
294
  */
295
  static public function requireCommonLib( $sFile ) {
296
- require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.$sFile );
297
  }
298
 
299
  /**
5
 
6
  class ICWP_WPSF_Foundation {
7
 
8
+ const DEFAULT_SERVICE_PREFIX = 'icwp_wpsf_';
9
+
10
  /**
11
  * @var array
12
  */
13
  private static $aDic;
14
 
15
+ /**
16
+ * @param string $sSuffix
17
+ * @return string
18
+ */
19
+ protected function prefix( $sSuffix ) {
20
+ return self::DEFAULT_SERVICE_PREFIX.$sSuffix;
21
+ }
22
+
23
  /**
24
  * @return ICWP_WPSF_DataProcessor
25
  */
135
  return self::getService( $sKey );
136
  }
137
 
138
+ /**
139
+ * @return ICWP_WPSF_ServiceProviders
140
+ */
141
+ public function loadServiceProviders() {
142
+ $sKey = 'icwp-serviceproviders';
143
+ if ( !self::isServiceReady( $sKey ) ) {
144
+ self::requireCommonLib( $sKey.'.php' );
145
+ self::setService( $sKey, ICWP_WPSF_ServiceProviders::GetInstance() );
146
+ }
147
+ return self::getService( $sKey );
148
+ }
149
+
150
  /**
151
  * @return ICWP_WPSF_Ssl
152
  */
315
  * @param string $sFile
316
  */
317
  static public function requireCommonLib( $sFile ) {
318
+ require_once( dirname( __FILE__ ).'/'.$sFile );
319
  }
320
 
321
  /**
src/common/icwp-optionsvo.php CHANGED
@@ -596,8 +596,15 @@ class ICWP_WPSF_OptionsVO extends ICWP_WPSF_Foundation {
596
  /**
597
  * @return bool
598
  */
599
- public function isModuleWhitelistExempt() {
600
- return (bool)$this->getFeatureProperty( 'whitelist_exempt' );
 
 
 
 
 
 
 
601
  }
602
 
603
  /**
@@ -707,29 +714,42 @@ class ICWP_WPSF_OptionsVO extends ICWP_WPSF_Foundation {
707
 
708
  /**
709
  * @param string $sOptKey
710
- * @param mixed $mValue
711
  * @return mixed
712
  */
713
- public function setOpt( $sOptKey, $mValue ) {
714
 
715
  // We can't use getOpt() to find the current value since we'll create an infinite loop
716
  $aOptionsValues = $this->getAllOptionsValues();
717
  $mCurrent = isset( $aOptionsValues[ $sOptKey ] ) ? $aOptionsValues[ $sOptKey ] : null;
718
 
719
- $mValue = $this->ensureOptValueState( $sOptKey, $mValue );
720
- if ( serialize( $mCurrent ) !== serialize( $mValue ) && $this->verifyCanSet( $sOptKey, $mValue ) ) {
 
 
 
 
 
 
 
 
721
  $this->setNeedSave( true );
722
 
723
  //Load the config and do some pre-set verification where possible. This will slowly grow.
724
  $aOption = $this->getRawData_SingleOption( $sOptKey );
725
  if ( !empty( $aOption[ 'type' ] ) ) {
726
- if ( $aOption[ 'type' ] == 'boolean' && !is_bool( $mValue ) ) {
727
  return $this->resetOptToDefault( $sOptKey );
728
  }
729
  }
730
  $this->setOldOptValue( $sOptKey, $mCurrent );
731
- $this->aOptionsValues[ $sOptKey ] = $mValue;
732
  }
 
 
 
 
 
733
  return true;
734
  }
735
 
596
  /**
597
  * @return bool
598
  */
599
+ public function isModuleRunIfWhitelisted() {
600
+ return (bool)$this->getFeatureProperty( 'run_if_whitelisted' );
601
+ }
602
+
603
+ /**
604
+ * @return bool
605
+ */
606
+ public function isModuleRunIfVerifiedBot() {
607
+ return (bool)$this->getFeatureProperty( 'run_if_verified_bot' );
608
  }
609
 
610
  /**
714
 
715
  /**
716
  * @param string $sOptKey
717
+ * @param mixed $mNewValue
718
  * @return mixed
719
  */
720
+ public function setOpt( $sOptKey, $mNewValue ) {
721
 
722
  // We can't use getOpt() to find the current value since we'll create an infinite loop
723
  $aOptionsValues = $this->getAllOptionsValues();
724
  $mCurrent = isset( $aOptionsValues[ $sOptKey ] ) ? $aOptionsValues[ $sOptKey ] : null;
725
 
726
+ $mNewValue = $this->ensureOptValueState( $sOptKey, $mNewValue );
727
+
728
+ // Here we try to ensure that values that are repeatedly changed properly reflect their changed
729
+ // states, as they may be reverted back to their original state and we "think" it's been changed.
730
+ $bValueIsDifferent = serialize( $mCurrent ) !== serialize( $mNewValue );
731
+ // basically if we're actually resetting back to the original value
732
+ $bIsResetting = $bValueIsDifferent && $this->isOptChanged( $sOptKey )
733
+ && ( serialize( $this->getOldValue( $sOptKey ) ) === serialize( $mNewValue ) );
734
+
735
+ if ( $bValueIsDifferent && $this->verifyCanSet( $sOptKey, $mNewValue ) ) {
736
  $this->setNeedSave( true );
737
 
738
  //Load the config and do some pre-set verification where possible. This will slowly grow.
739
  $aOption = $this->getRawData_SingleOption( $sOptKey );
740
  if ( !empty( $aOption[ 'type' ] ) ) {
741
+ if ( $aOption[ 'type' ] == 'boolean' && !is_bool( $mNewValue ) ) {
742
  return $this->resetOptToDefault( $sOptKey );
743
  }
744
  }
745
  $this->setOldOptValue( $sOptKey, $mCurrent );
746
+ $this->aOptionsValues[ $sOptKey ] = $mNewValue;
747
  }
748
+
749
+ if ( $bIsResetting ) {
750
+ unset( $this->aOld[ $sOptKey ] );
751
+ }
752
+
753
  return true;
754
  }
755
 
src/common/icwp-serviceproviders.php ADDED
@@ -0,0 +1,455 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( class_exists( 'ICWP_WPSF_ServiceProviders', false ) ) {
3
+ return;
4
+ }
5
+
6
+ /**
7
+ * Class ICWP_WPSF_ServiceProviders
8
+ */
9
+ class ICWP_WPSF_ServiceProviders extends ICWP_WPSF_Foundation {
10
+
11
+ /**
12
+ * @var string
13
+ */
14
+ protected $sPrefix = '';
15
+
16
+ /**
17
+ * @var ICWP_WPSF_ServiceProviders
18
+ */
19
+ protected static $oInstance = null;
20
+
21
+ /**
22
+ * @return ICWP_WPSF_ServiceProviders
23
+ */
24
+ public static function GetInstance() {
25
+ if ( is_null( self::$oInstance ) ) {
26
+ self::$oInstance = new self();
27
+ }
28
+ return self::$oInstance;
29
+ }
30
+
31
+ /**
32
+ * @return string[][]
33
+ */
34
+ public function getIps_CloudFlare() {
35
+ $oWp = $this->loadWp();
36
+ $aIps = $oWp->getTransient( $this->prefix( 'serviceips_cloudflare' ) );
37
+ if ( empty( $aIps ) ) {
38
+ $aIps = array(
39
+ 4 => $this->downloadServiceIps_Cloudflare( 4 ),
40
+ 6 => $this->downloadServiceIps_Cloudflare( 6 )
41
+ );
42
+ $oWp->setTransient( $this->prefix( 'serviceips_cloudflare' ), $aIps, WEEK_IN_SECONDS*4 );
43
+ }
44
+ return $aIps;
45
+ }
46
+
47
+ /**
48
+ * @return string[]
49
+ */
50
+ public function getIps_CloudFlareV4() {
51
+ $aIps = $this->getIps_CloudFlare();
52
+ return $aIps[ 4 ];
53
+ }
54
+
55
+ /**
56
+ * @return string[]
57
+ */
58
+ public function getIps_CloudFlareV6() {
59
+ $aIps = $this->getIps_CloudFlare();
60
+ return $aIps[ 6 ];
61
+ }
62
+
63
+ /**
64
+ * @return string[]
65
+ */
66
+ public function getIps_DuckDuckGo() {
67
+ return array( '107.20.237.51', '23.21.226.191', '107.21.1.8', '54.208.102.37' );
68
+ }
69
+
70
+ /**
71
+ * @return array[]
72
+ */
73
+ public function getIps_Pingdom() {
74
+ $oWp = $this->loadWp();
75
+ $aIps = $oWp->getTransient( $this->prefix( 'serviceips_pingdom' ) );
76
+ if ( empty( $aIps ) ) {
77
+ $aIps = array(
78
+ 4 => $this->downloadServiceIps_Pingdom( 4 ),
79
+ 6 => $this->downloadServiceIps_Pingdom( 6 )
80
+ );
81
+ $oWp->setTransient( $this->prefix( 'serviceips_pingdom' ), $aIps, WEEK_IN_SECONDS*4 );
82
+ }
83
+ return $aIps;
84
+ }
85
+
86
+ /**
87
+ * @return string[]
88
+ */
89
+ public function getIps_Statuscake() {
90
+ $oWp = $this->loadWp();
91
+ $aIps = $oWp->getTransient( $this->prefix( 'serviceips_statuscake' ) );
92
+ if ( empty( $aIps ) || !is_array( $aIps ) ) {
93
+ $aIps = $this->downloadServiceIps_StatusCake();
94
+ $oWp->setTransient( $this->prefix( 'serviceips_statuscake' ), $aIps, WEEK_IN_SECONDS*4 );
95
+ }
96
+ return $aIps;
97
+ }
98
+
99
+ /**
100
+ * @return array[]
101
+ */
102
+ public function getIps_UptimeRobot() {
103
+ $oWp = $this->loadWp();
104
+ $aIps = $oWp->getTransient( $this->prefix( 'serviceips_uptimerobot' ) );
105
+ if ( empty( $aIps ) ) {
106
+ $aIps = array(
107
+ 4 => $this->downloadServiceIps_UptimeRobot( 4 ),
108
+ 6 => $this->downloadServiceIps_UptimeRobot( 6 )
109
+ );
110
+ $oWp->setTransient( $this->prefix( 'serviceips_uptimerobot' ), $aIps, WEEK_IN_SECONDS*4 );
111
+ }
112
+ return $aIps;
113
+ }
114
+
115
+ /**
116
+ * @param string $sIp
117
+ * @param string $sUserAgent
118
+ * @return bool
119
+ */
120
+ public function isIp_AppleBot( $sIp, $sUserAgent ) {
121
+ $oWp = $this->loadWp();
122
+
123
+ $sStoreKey = $this->prefix( 'serviceips_applebot' );
124
+ $aIps = $oWp->getTransient( $sStoreKey );
125
+ if ( !is_array( $aIps ) ) {
126
+ $aIps = array();
127
+ }
128
+
129
+ if ( !in_array( $sIp, $aIps ) && $this->verifyIp_AppleBot( $sIp, $sUserAgent ) ) {
130
+ $aIps[] = $sIp;
131
+ $aIps = $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
132
+ }
133
+
134
+ return in_array( $sIp, $aIps );
135
+ }
136
+
137
+ /**
138
+ * @param string $sIp
139
+ * @param string $sUserAgent
140
+ * @return bool
141
+ */
142
+ public function isIp_BaiduBot( $sIp, $sUserAgent ) {
143
+ $oWp = $this->loadWp();
144
+
145
+ $sStoreKey = $this->prefix( 'serviceips_baidubot' );
146
+ $aIps = $oWp->getTransient( $sStoreKey );
147
+ if ( !is_array( $aIps ) ) {
148
+ $aIps = array();
149
+ }
150
+
151
+ if ( !in_array( $sIp, $aIps ) && $this->verifyIp_BaiduBot( $sIp, $sUserAgent ) ) {
152
+ $aIps[] = $sIp;
153
+ $aIps = $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
154
+ }
155
+
156
+ return in_array( $sIp, $aIps );
157
+ }
158
+
159
+ /**
160
+ * @param string $sIp
161
+ * @param string $sUserAgent
162
+ * @return bool
163
+ */
164
+ public function isIp_BingBot( $sIp, $sUserAgent ) {
165
+ $oWp = $this->loadWp();
166
+
167
+ $sStoreKey = $this->prefix( 'serviceips_bingbot' );
168
+ $aIps = $oWp->getTransient( $sStoreKey );
169
+ if ( !is_array( $aIps ) ) {
170
+ $aIps = array();
171
+ }
172
+
173
+ if ( !in_array( $sIp, $aIps ) && $this->verifyIp_BingBot( $sIp, $sUserAgent ) ) {
174
+ $aIps[] = $sIp;
175
+ $aIps = $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
176
+ }
177
+
178
+ return in_array( $sIp, $aIps );
179
+ }
180
+
181
+ /**
182
+ * @param string $sIp
183
+ * @return bool
184
+ */
185
+ public function isIp_Cloudflare( $sIp ) {
186
+ $bIs = false;
187
+ try {
188
+ $oIp = $this->loadIpService();
189
+ if ( $oIp->getIpVersion( $sIp ) == 4 ) {
190
+ $bIs = $oIp->checkIp( $sIp, $this->getIps_CloudFlareV4() );
191
+ }
192
+ else {
193
+ $bIs = $oIp->checkIp( $sIp, $this->getIps_CloudFlareV6() );
194
+ }
195
+ }
196
+ catch ( Exception $oE ) {
197
+ }
198
+ return $bIs;
199
+ }
200
+
201
+ /**
202
+ * https://duckduckgo.com/duckduckbot
203
+ * @param string $sIp
204
+ * @param string $sUserAgent
205
+ * @return bool
206
+ */
207
+ public function isIp_DuckDuckGoBot( $sIp, $sUserAgent ) {
208
+ $bIsBot = false;
209
+ // We check the useragent if available
210
+ if ( is_null( $sUserAgent ) || stripos( $sUserAgent, 'DuckDuckBot' ) !== false ) {
211
+ $bIsBot = in_array( $sIp, $this->getIps_DuckDuckGo() );
212
+ }
213
+ return $bIsBot;
214
+ }
215
+
216
+ /**
217
+ * https://support.google.com/webmasters/answer/80553?hl=en
218
+ * @param string $sIp
219
+ * @param string $sUserAgent
220
+ * @return bool
221
+ */
222
+ public function isIp_GoogleBot( $sIp, $sUserAgent ) {
223
+ $oWp = $this->loadWp();
224
+
225
+ $sStoreKey = $this->prefix( 'serviceips_googlebot' );
226
+ $aIps = $oWp->getTransient( $sStoreKey );
227
+ if ( !is_array( $aIps ) ) {
228
+ $aIps = array();
229
+ }
230
+
231
+ if ( !in_array( $sIp, $aIps ) && $this->verifyIp_GoogleBot( $sIp, $sUserAgent ) ) {
232
+ $aIps[] = $sIp;
233
+ $aIps = $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
234
+ }
235
+
236
+ return in_array( $sIp, $aIps );
237
+ }
238
+
239
+ /**
240
+ * @param string $sIp
241
+ * @param string $sAgent
242
+ * @return bool
243
+ */
244
+ public function isIp_Statuscake( $sIp, $sAgent ) {
245
+ $bIsIp = false;
246
+ if ( stripos( $sAgent, 'StatusCake' ) !== false ) {
247
+ $aIps = $this->getIps_Statuscake();
248
+ $bIsIp = in_array( $sIp, $aIps );
249
+ }
250
+ return $bIsIp;
251
+ }
252
+
253
+ /**
254
+ * @param string $sIp
255
+ * @param string $sAgent
256
+ * @return bool
257
+ */
258
+ public function isIp_Pingdom( $sIp, $sAgent ) {
259
+ $bIsIp = false;
260
+ if ( stripos( $sAgent, 'pingdom.com' ) !== false ) {
261
+ $aIps = $this->getIps_Pingdom();
262
+ $bIsIp = in_array( $sIp, $aIps[ $this->loadIpService()->getIpVersion( $sIp ) ] );
263
+ }
264
+ return $bIsIp;
265
+ }
266
+
267
+ /**
268
+ * @param string $sIp
269
+ * @param string $sAgent
270
+ * @return bool
271
+ */
272
+ public function isIp_UptimeRobot( $sIp, $sAgent ) {
273
+ $bIsIp = false;
274
+ if ( stripos( $sAgent, 'UptimeRobot' ) !== false ) {
275
+ $aIps = $this->getIps_UptimeRobot();
276
+ $bIsIp = in_array( $sIp, $aIps[ $this->loadIpService()->getIpVersion( $sIp ) ] );
277
+ }
278
+ return $bIsIp;
279
+ }
280
+
281
+ /**
282
+ * https://yandex.com/support/webmaster/robot-workings/check-yandex-robots.html
283
+ * @param string $sIp
284
+ * @param string $sUserAgent
285
+ * @return bool
286
+ */
287
+ public function isIp_YandexBot( $sIp, $sUserAgent ) {
288
+ $oWp = $this->loadWp();
289
+
290
+ $sStoreKey = $this->prefix( 'serviceips_yandexbot' );
291
+ $aIps = $oWp->getTransient( $sStoreKey );
292
+ if ( !is_array( $aIps ) ) {
293
+ $aIps = array();
294
+ }
295
+
296
+ if ( !in_array( $sIp, $aIps ) && $this->verifyIp_YandexBot( $sIp, $sUserAgent ) ) {
297
+ $aIps[] = $sIp;
298
+ $aIps = $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
299
+ }
300
+
301
+ return in_array( $sIp, $aIps );
302
+ }
303
+
304
+ /**
305
+ * https://yandex.com/support/webmaster/robot-workings/check-yandex-robots.html
306
+ * @param string $sIp
307
+ * @param string $sUserAgent
308
+ * @return bool
309
+ */
310
+ public function isIp_YahooBot( $sIp, $sUserAgent ) {
311
+ $oWp = $this->loadWp();
312
+
313
+ $sStoreKey = $this->prefix( 'serviceips_yahoobot' );
314
+ $aIps = $oWp->getTransient( $sStoreKey );
315
+ if ( !is_array( $aIps ) ) {
316
+ $aIps = array();
317
+ }
318
+
319
+ if ( !in_array( $sIp, $aIps ) && $this->verifyIp_YahooBot( $sIp, $sUserAgent ) ) {
320
+ $aIps[] = $sIp;
321
+ $aIps = $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
322
+ }
323
+
324
+ return in_array( $sIp, $aIps );
325
+ }
326
+
327
+ /**
328
+ * https://support.apple.com/en-gb/HT204683
329
+ * https://discussions.apple.com/thread/7090135
330
+ * Apple IPs start with '17.'
331
+ * @param string $sIp
332
+ * @param string $sUserAgent
333
+ * @return bool
334
+ */
335
+ private function verifyIp_AppleBot( $sIp, $sUserAgent = '' ) {
336
+ return ( $this->loadIpService()->getIpVersion( $sIp ) != 4 || strpos( $sIp, '17.' ) === 0 )
337
+ && $this->isIpOfBot( 'Applebot/', '#.*\.applebot.apple.com\.?$#i', $sIp, $sUserAgent );
338
+ }
339
+
340
+ /**
341
+ * @param string $sIp
342
+ * @param string $sUserAgent
343
+ * @return bool
344
+ */
345
+ private function verifyIp_BaiduBot( $sIp, $sUserAgent = '' ) {
346
+ return $this->isIpOfBot( 'baidu', '#.*\.crawl\.baidu\.(com|jp)\.?$#i', $sIp, $sUserAgent );
347
+ }
348
+
349
+ /**
350
+ * @param string $sIp
351
+ * @param string $sUserAgent
352
+ * @return bool
353
+ */
354
+ private function verifyIp_BingBot( $sIp, $sUserAgent = '' ) {
355
+ return $this->isIpOfBot( 'bingbot', '#.*\.search\.msn\.com\.?$#i', $sIp, $sUserAgent );
356
+ }
357
+
358
+ /**
359
+ * @param string $sIp
360
+ * @param string $sUserAgent
361
+ * @return bool
362
+ */
363
+ private function verifyIp_GoogleBot( $sIp, $sUserAgent = '' ) {
364
+ return $this->isIpOfBot( 'Googlebot', '#.*\.google(bot)?\.com\.?$#i', $sIp, $sUserAgent );
365
+ }
366
+
367
+ /**
368
+ * @param string $sIp
369
+ * @param string $sUserAgent
370
+ * @return bool
371
+ */
372
+ private function verifyIp_YandexBot( $sIp, $sUserAgent = '' ) {
373
+ return $this->isIpOfBot( 'yandex.com/bots', '#.*\.yandex?\.(com|ru|net)\.?$#i', $sIp, $sUserAgent );
374
+ }
375
+
376
+ /**
377
+ * @param string $sIp
378
+ * @param string $sUserAgent
379
+ * @return bool
380
+ */
381
+ private function verifyIp_YahooBot( $sIp, $sUserAgent = '' ) {
382
+ return $this->isIpOfBot( 'yahoo!', '#.*\.crawl\.yahoo\.net\.?$#i', $sIp, $sUserAgent );
383
+ }
384
+
385
+ /**
386
+ * Will test useragent, then attempt to resolve to hostname and back again
387
+ * https://www.elephate.com/detect-verify-crawlers/
388
+ * @param string $sBotUserAgent
389
+ * @param string $sBotHostPattern
390
+ * @param string $sReqIp
391
+ * @param string $sReqUserAgent
392
+ * @return bool
393
+ */
394
+ private function isIpOfBot( $sBotUserAgent, $sBotHostPattern, $sReqIp, $sReqUserAgent = '' ) {
395
+ $bIsBot = false;
396
+
397
+ // We check the useragent if available
398
+ if ( is_null( $sReqUserAgent ) || stripos( $sReqUserAgent, $sBotUserAgent ) !== false ) {
399
+ $sHost = @gethostbyaddr( $sReqIp ); // returns the ip on failure
400
+ if ( !empty( $sHost ) && ( $sHost != $sReqIp )
401
+ && preg_match( $sBotHostPattern, $sHost ) && gethostbyname( $sHost ) === $sReqIp ) {
402
+ $bIsBot = true;
403
+ }
404
+ }
405
+ return $bIsBot;
406
+ }
407
+
408
+ /**
409
+ * @param int $sIpVersion
410
+ * @return string[]
411
+ */
412
+ private function downloadServiceIps_Cloudflare( $sIpVersion = 4 ) {
413
+ if ( !in_array( (int)$sIpVersion, array( 4, 6 ) ) ) {
414
+ $sIpVersion = 4;
415
+ }
416
+ $sUrl = 'https://www.cloudflare.com/ips-v'.$sIpVersion;
417
+ return array_filter( array_map( 'trim', explode( "\n", $this->loadFS()->getUrlContent( $sUrl ) ) ) );
418
+ }
419
+
420
+ /**
421
+ * @param int $sIpVersion
422
+ * @return string[]
423
+ */
424
+ private function downloadServiceIps_Pingdom( $sIpVersion = 4 ) {
425
+ $sUrl = sprintf( 'https://my.pingdom.com/probes/ipv%s', $sIpVersion );
426
+ return array_filter( array_map( 'trim', explode( "\n", $this->loadFS()->getUrlContent( $sUrl ) ) ) );
427
+ }
428
+
429
+ /**
430
+ * @return string[]
431
+ */
432
+ private function downloadServiceIps_StatusCake() {
433
+ $aIps = array();
434
+ $aData = @json_decode( $this->loadFS()
435
+ ->getUrlContent( 'https://app.statuscake.com/Workfloor/Locations.php?format=json' ), true );
436
+ if ( is_array( $aData ) ) {
437
+ foreach ( $aData as $aItem ) {
438
+ $aIps[] = $aItem[ 'ip' ];
439
+ }
440
+ }
441
+ return $aIps;
442
+ }
443
+
444
+ /**
445
+ * @param int $sIpVersion
446
+ * @return string[]
447
+ */
448
+ private function downloadServiceIps_UptimeRobot( $sIpVersion = 4 ) {
449
+ if ( !in_array( (int)$sIpVersion, array( 4, 6 ) ) ) {
450
+ $sIpVersion = 4;
451
+ }
452
+ $sUrl = sprintf( 'https://uptimerobot.com/inc/files/ips/IPv%s.txt', $sIpVersion );
453
+ return array_filter( array_map( 'trim', explode( "\n", $this->loadFS()->getUrlContent( $sUrl ) ) ) );
454
+ }
455
+ }
src/common/icwp-usermeta.php CHANGED
@@ -6,6 +6,8 @@ if ( class_exists( 'ICWP_UserMeta', false ) ) {
6
  /**
7
  * @property string $email_secret
8
  * @property bool $email_validated
 
 
9
  * @property string $ga_secret
10
  * @property bool $ga_validated
11
  * @property array $hash_loginmfa
@@ -14,9 +16,7 @@ if ( class_exists( 'ICWP_UserMeta', false ) ) {
14
  * @property int $pass_check_failed_at
15
  * @property string $yubi_secret
16
  * @property bool $yubi_validated
17
- * @property string $code_tfaemail
18
  * @property int $last_login_at
19
- * @property int $login_intent_expires_at
20
  * @property string $prefix
21
  * @property int $user_id
22
  * @property bool $wc_social_login_valid
6
  /**
7
  * @property string $email_secret
8
  * @property bool $email_validated
9
+ * @property string $backupcode_secret
10
+ * @property string $backupcode_validated
11
  * @property string $ga_secret
12
  * @property bool $ga_validated
13
  * @property array $hash_loginmfa
16
  * @property int $pass_check_failed_at
17
  * @property string $yubi_secret
18
  * @property bool $yubi_validated
 
19
  * @property int $last_login_at
 
20
  * @property string $prefix
21
  * @property int $user_id
22
  * @property bool $wc_social_login_valid
src/common/icwp-wpfunctions-plugins.php CHANGED
@@ -292,14 +292,15 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
292
  * @param string $sPluginFile
293
  * @return string
294
  */
295
- public function getLinkPluginDeactivate( $sPluginFile ) {
296
- $sUrl = self_admin_url( 'plugins.php' );
297
- $aQueryArgs = array(
298
- 'action' => 'deactivate',
299
- 'plugin' => urlencode( $sPluginFile ),
300
- '_wpnonce' => wp_create_nonce( 'deactivate-plugin_'.$sPluginFile )
 
 
301
  );
302
- return add_query_arg( $aQueryArgs, $sUrl );
303
  }
304
 
305
  /**
292
  * @param string $sPluginFile
293
  * @return string
294
  */
295
+ public function getUrl_Deactivate( $sPluginFile ) {
296
+ return add_query_arg(
297
+ array(
298
+ 'action' => 'deactivate',
299
+ 'plugin' => urlencode( $sPluginFile ),
300
+ '_wpnonce' => wp_create_nonce( 'deactivate-plugin_'.$sPluginFile )
301
+ ),
302
+ self_admin_url( 'plugins.php' )
303
  );
 
304
  }
305
 
306
  /**
src/common/lib/composer.lock CHANGED
@@ -297,16 +297,16 @@
297
  },
298
  {
299
  "name": "nesbot/carbon",
300
- "version": "1.33.0",
301
  "source": {
302
  "type": "git",
303
  "url": "https://github.com/briannesbitt/Carbon.git",
304
- "reference": "55667c1007a99e82030874b1bb14d24d07108413"
305
  },
306
  "dist": {
307
  "type": "zip",
308
- "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/55667c1007a99e82030874b1bb14d24d07108413",
309
- "reference": "55667c1007a99e82030874b1bb14d24d07108413",
310
  "shasum": ""
311
  },
312
  "require": {
@@ -348,7 +348,7 @@
348
  "datetime",
349
  "time"
350
  ],
351
- "time": "2018-08-07T08:39:47+00:00"
352
  },
353
  {
354
  "name": "symfony/polyfill-ctype",
297
  },
298
  {
299
  "name": "nesbot/carbon",
300
+ "version": "1.34.0",
301
  "source": {
302
  "type": "git",
303
  "url": "https://github.com/briannesbitt/Carbon.git",
304
+ "reference": "1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33"
305
  },
306
  "dist": {
307
  "type": "zip",
308
+ "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33",
309
+ "reference": "1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33",
310
  "shasum": ""
311
  },
312
  "require": {
348
  "datetime",
349
  "time"
350
  ],
351
+ "time": "2018-09-20T19:36:25+00:00"
352
  },
353
  {
354
  "name": "symfony/polyfill-ctype",
src/common/lib/vendor/composer/installed.json CHANGED
@@ -211,63 +211,6 @@
211
  "shim"
212
  ]
213
  },
214
- {
215
- "name": "nesbot/carbon",
216
- "version": "1.33.0",
217
- "version_normalized": "1.33.0.0",
218
- "source": {
219
- "type": "git",
220
- "url": "https://github.com/briannesbitt/Carbon.git",
221
- "reference": "55667c1007a99e82030874b1bb14d24d07108413"
222
- },
223
- "dist": {
224
- "type": "zip",
225
- "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/55667c1007a99e82030874b1bb14d24d07108413",
226
- "reference": "55667c1007a99e82030874b1bb14d24d07108413",
227
- "shasum": ""
228
- },
229
- "require": {
230
- "php": ">=5.3.9",
231
- "symfony/translation": "~2.6 || ~3.0 || ~4.0"
232
- },
233
- "require-dev": {
234
- "friendsofphp/php-cs-fixer": "~2",
235
- "phpunit/phpunit": "^4.8.35 || ^5.7"
236
- },
237
- "time": "2018-08-07T08:39:47+00:00",
238
- "type": "library",
239
- "extra": {
240
- "laravel": {
241
- "providers": [
242
- "Carbon\\Laravel\\ServiceProvider"
243
- ]
244
- }
245
- },
246
- "installation-source": "dist",
247
- "autoload": {
248
- "psr-4": {
249
- "": "src/"
250
- }
251
- },
252
- "notification-url": "https://packagist.org/downloads/",
253
- "license": [
254
- "MIT"
255
- ],
256
- "authors": [
257
- {
258
- "name": "Brian Nesbitt",
259
- "email": "brian@nesbot.com",
260
- "homepage": "http://nesbot.com"
261
- }
262
- ],
263
- "description": "A simple API extension for DateTime.",
264
- "homepage": "http://carbon.nesbot.com",
265
- "keywords": [
266
- "date",
267
- "datetime",
268
- "time"
269
- ]
270
- },
271
  {
272
  "name": "symfony/polyfill-ctype",
273
  "version": "v1.9.0",
@@ -611,5 +554,62 @@
611
  ],
612
  "description": "Symfony Translation Component",
613
  "homepage": "https://symfony.com"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
614
  }
615
  ]
211
  "shim"
212
  ]
213
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  {
215
  "name": "symfony/polyfill-ctype",
216
  "version": "v1.9.0",
554
  ],
555
  "description": "Symfony Translation Component",
556
  "homepage": "https://symfony.com"
557
+ },
558
+ {
559
+ "name": "nesbot/carbon",
560
+ "version": "1.34.0",
561
+ "version_normalized": "1.34.0.0",
562
+ "source": {
563
+ "type": "git",
564
+ "url": "https://github.com/briannesbitt/Carbon.git",
565
+ "reference": "1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33"
566
+ },
567
+ "dist": {
568
+ "type": "zip",
569
+ "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33",
570
+ "reference": "1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33",
571
+ "shasum": ""
572
+ },
573
+ "require": {
574
+ "php": ">=5.3.9",
575
+ "symfony/translation": "~2.6 || ~3.0 || ~4.0"
576
+ },
577
+ "require-dev": {
578
+ "friendsofphp/php-cs-fixer": "~2",
579
+ "phpunit/phpunit": "^4.8.35 || ^5.7"
580
+ },
581
+ "time": "2018-09-20T19:36:25+00:00",
582
+ "type": "library",
583
+ "extra": {
584
+ "laravel": {
585
+ "providers": [
586
+ "Carbon\\Laravel\\ServiceProvider"
587
+ ]
588
+ }
589
+ },
590
+ "installation-source": "dist",
591
+ "autoload": {
592
+ "psr-4": {
593
+ "": "src/"
594
+ }
595
+ },
596
+ "notification-url": "https://packagist.org/downloads/",
597
+ "license": [
598
+ "MIT"
599
+ ],
600
+ "authors": [
601
+ {
602
+ "name": "Brian Nesbitt",
603
+ "email": "brian@nesbot.com",
604
+ "homepage": "http://nesbot.com"
605
+ }
606
+ ],
607
+ "description": "A simple API extension for DateTime.",
608
+ "homepage": "http://carbon.nesbot.com",
609
+ "keywords": [
610
+ "date",
611
+ "datetime",
612
+ "time"
613
+ ]
614
  }
615
  ]
src/common/lib/vendor/nesbot/carbon/src/Carbon/Lang/ru.php CHANGED
@@ -11,19 +11,19 @@
11
 
12
  return array(
13
  'year' => ':count год|:count года|:count лет',
14
- 'y' => ':count год|:count года|:count лет',
15
  'month' => ':count месяц|:count месяца|:count месяцев',
16
- 'm' => ':count месяц|:count месяца|:count месяцев',
17
  'week' => ':count неделю|:count недели|:count недель',
18
- 'w' => ':count неделю|:count недели|:count недель',
19
  'day' => ':count день|:count дня|:count дней',
20
- 'd' => ':count день|:count дня|:count дней',
21
  'hour' => ':count час|:count часа|:count часов',
22
- 'h' => ':count час|:count часа|:count часов',
23
  'minute' => ':count минуту|:count минуты|:count минут',
24
- 'min' => ':count минуту|:count минуты|:count минут',
25
  'second' => ':count секунду|:count секунды|:count секунд',
26
- 's' => ':count секунду|:count секунды|:count секунд',
27
  'ago' => ':time назад',
28
  'from_now' => 'через :time',
29
  'after' => ':time после',
11
 
12
  return array(
13
  'year' => ':count год|:count года|:count лет',
14
+ 'y' => ':count г|:count г|:count л',
15
  'month' => ':count месяц|:count месяца|:count месяцев',
16
+ 'm' => ':count м|:count м|:count м',
17
  'week' => ':count неделю|:count недели|:count недель',
18
+ 'w' => ':count н|:count н|:count н',
19
  'day' => ':count день|:count дня|:count дней',
20
+ 'd' => ':count д|:count д|:count д',
21
  'hour' => ':count час|:count часа|:count часов',
22
+ 'h' => ':count ч|:count ч|:count ч',
23
  'minute' => ':count минуту|:count минуты|:count минут',
24
+ 'min' => ':count мин|:count мин|:count мин',
25
  'second' => ':count секунду|:count секунды|:count секунд',
26
+ 's' => ':count с|:count с|:count с',
27
  'ago' => ':time назад',
28
  'from_now' => 'через :time',
29
  'after' => ':time после',
src/common/lib/vendor/nesbot/carbon/src/JsonSerializable.php CHANGED
@@ -1,16 +1,18 @@
1
  <?php
2
 
3
- interface JsonSerializable
4
- {
5
- /**
6
- * Specify data which should be serialized to JSON.
7
- *
8
- * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
9
- *
10
- * @return mixed data which can be serialized by <b>json_encode</b>,
11
- * which is a value of any type other than a resource.
12
- *
13
- * @since 5.4.0
14
- */
15
- public function jsonSerialize();
 
 
16
  }
1
  <?php
2
 
3
+ if (!interface_exists('JsonSerializable')) {
4
+ interface JsonSerializable
5
+ {
6
+ /**
7
+ * Specify data which should be serialized to JSON.
8
+ *
9
+ * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
10
+ *
11
+ * @return mixed data which can be serialized by <b>json_encode</b>,
12
+ * which is a value of any type other than a resource.
13
+ *
14
+ * @since 5.4.0
15
+ */
16
+ public function jsonSerialize();
17
+ }
18
  }
src/common/wp-users.php CHANGED
@@ -132,11 +132,7 @@ class ICWP_WPSF_WpUsers extends ICWP_WPSF_Foundation {
132
  * @return null|WP_User
133
  */
134
  public function getCurrentWpUser() {
135
- $oUser = null;
136
- if ( $this->isUserLoggedIn() ) {
137
- $oUser = wp_get_current_user();
138
- }
139
- return $oUser;
140
  }
141
 
142
  /**
132
  * @return null|WP_User
133
  */
134
  public function getCurrentWpUser() {
135
+ return $this->isUserLoggedIn() ? wp_get_current_user() : null;
 
 
 
 
136
  }
137
 
138
  /**
src/config/feature-admin_access_restriction.php CHANGED
@@ -1,336 +1,351 @@
1
  {
2
- "slug": "admin_access_restriction",
3
- "properties": {
4
- "slug": "admin_access_restriction",
5
- "name": "Security Admin",
6
  "show_module_menu_item": true,
7
- "storage_key": "admin_access_restriction",
8
- "tagline": "Protect your Security Plugin, not just your WordPress site",
9
- "menu_title": "Security Admin",
10
- "show_central": true,
11
- "access_restricted": true,
12
- "premium": false,
13
- "order": 20
 
 
14
  },
15
  "admin_notices": {
16
  "certain-options-restricted": {
17
- "id": "certain-options-restricted",
18
- "schedule": "conditions",
19
  "valid_admin": true,
20
- "type": "warning"
21
  },
22
- "admin-users-restricted": {
23
- "id": "admin-users-restricted",
24
- "schedule": "conditions",
25
  "valid_admin": true,
26
- "type": "warning"
 
27
  }
28
  },
29
- "sections": [
30
  {
31
- "slug": "section_admin_access_restriction_settings",
32
- "primary": true,
33
- "title": "Security Admin Restriction Settings",
34
  "title_short": "Security Admin Settings",
35
- "summary": [
36
  "Purpose - Restrict access using a simple Access Key.",
37
  "Recommendation - Use of this feature is highly recommend."
38
  ]
39
  },
40
  {
41
- "slug": "section_admin_access_restriction_areas",
42
- "title": "Security Admin Restriction Zones",
43
  "title_short": "Access Restriction Zones",
44
- "summary": [
45
  "Purpose - Restricts access to key WordPress areas for all users not authenticated with the Security Admin Access system.",
46
  "Recommendation - Use of this feature is highly recommend."
47
  ]
48
  },
49
  {
50
- "slug": "section_whitelabel",
51
- "title": "Shield White Label",
52
  "title_short": "White Label",
53
- "summary": [
54
  "Purpose - Rename and re-brand the Shield Security plugin for your client site installations."
55
  ]
56
  },
57
  {
58
- "slug": "section_enable_plugin_feature_admin_access_restriction",
59
- "title": "Enable Module: WordPress Security Admin",
60
  "title_short": "Disable Module",
61
- "summary": [
62
  "Purpose - Restricts access to this plugin preventing unauthorized changes to your security settings.",
63
  "Recommendation - Keep the Security Admin feature turned on.",
64
  "You need to also enter a new Access Key to enable this feature."
65
  ]
66
  },
67
  {
68
- "slug": "section_non_ui",
69
  "hidden": true
70
  }
71
  ],
72
- "options": [
73
  {
74
- "key": "enable_admin_access_restriction",
75
- "section": "section_enable_plugin_feature_admin_access_restriction",
76
- "default": "Y",
77
- "type": "checkbox",
78
- "link_info": "https://icwp.io/40",
79
- "link_blog": "https://icwp.io/wpsf02",
80
- "name": "Enable Security Admin",
81
- "summary": "Enforce Security Admin Access Restriction",
82
  "description": "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."
83
  },
84
  {
85
- "key": "admin_access_key",
86
- "section": "section_admin_access_restriction_settings",
87
- "sensitive": true,
88
- "default": "",
89
- "type": "password",
90
- "link_info": "https://icwp.io/42",
91
- "link_blog": "",
92
- "name": "Security Admin Access Key",
93
- "summary": "Provide/Update Security Admin Access Key",
94
  "description": "Careful: If you forget this, you could potentially lock yourself out from using this plugin."
95
  },
96
  {
97
- "key": "admin_access_timeout",
98
- "section": "section_admin_access_restriction_settings",
99
- "default": 30,
100
- "type": "integer",
101
- "min": 1,
102
- "link_info": "https://icwp.io/41",
103
- "link_blog": "",
104
- "name": "Security Admin Timeout",
105
- "summary": "Specify An Automatic Timeout Interval For Security Admin Access",
106
  "description": "This will automatically expire your Security Admin Session. Does not apply until you enter the access key again. Default: 60 minutes."
107
  },
108
  {
109
- "key": "admin_access_restrict_options",
110
- "section": "section_admin_access_restriction_areas",
111
- "default": "Y",
112
- "type": "checkbox",
113
- "link_info": "https://icwp.io/a0",
114
- "link_blog": "https://icwp.io/wpsf32",
115
- "name": "Pages",
116
- "summary": "Restrict Access To Key WordPress Posts And Pages Actions",
117
  "description": "Careful: This will restrict access to page/post creation, editing and deletion. Note: Selecting 'Edit' will also restrict all other options."
118
  },
119
  {
120
- "key": "admin_access_restrict_admin_users",
121
- "section": "section_admin_access_restriction_areas",
122
- "default": "N",
123
- "type": "checkbox",
124
- "link_info": "https://icwp.io/a0",
125
- "link_blog": "",
126
- "name": "Admin Users",
127
- "summary": "Restrict Access To Create/Delete/Modify Other Admin Users",
128
  "description": "Careful: This will restrict the ability of WordPress administrators from creating, modifying or promoting other administrators."
129
  },
130
  {
131
- "key": "admin_access_restrict_plugins",
132
- "section": "section_admin_access_restriction_areas",
133
- "type": "multiple_select",
134
- "default": null,
135
  "value_options": [
136
  {
137
  "value_key": "activate_plugins",
138
- "text": "Activate"
139
  },
140
  {
141
  "value_key": "install_plugins",
142
- "text": "Install"
143
  },
144
  {
145
  "value_key": "update_plugins",
146
- "text": "Update"
147
  },
148
  {
149
  "value_key": "delete_plugins",
150
- "text": "Delete"
151
  }
152
  ],
153
- "link_info": "https://icwp.io/a0",
154
- "link_blog": "https://icwp.io/wpsf21",
155
- "summary": "Restrict Access To Key WordPress Plugin Actions",
156
- "description": "Careful: This will restrict access to plugin installation, update, activation and deletion. Note: Selecting 'Activate' will also restrict all other options."
157
  },
158
  {
159
- "key": "admin_access_restrict_themes",
160
- "section": "section_admin_access_restriction_areas",
161
- "type": "multiple_select",
162
- "default": null,
163
  "value_options": [
164
  {
165
  "value_key": "switch_themes",
166
- "text": "Activate"
167
  },
168
  {
169
  "value_key": "edit_theme_options",
170
- "text": "Edit Theme Options"
171
  },
172
  {
173
  "value_key": "install_themes",
174
- "text": "Install"
175
  },
176
  {
177
  "value_key": "update_themes",
178
- "text": "Update"
179
  },
180
  {
181
  "value_key": "delete_themes",
182
- "text": "Delete"
183
  }
184
  ],
185
- "link_info": "https://icwp.io/a0",
186
- "link_blog": "https://icwp.io/wpsf21",
187
- "summary": "Restrict Access To WordPress Theme Actions",
188
- "description": "Careful: This will restrict access to theme installation, update, activation and deletion."
189
  },
190
  {
191
- "key": "admin_access_restrict_posts",
192
- "section": "section_admin_access_restriction_areas",
193
- "type": "multiple_select",
194
- "default": null,
195
  "value_options": [
196
  {
197
  "value_key": "edit",
198
- "text": "Create / Edit"
199
  },
200
  {
201
  "value_key": "publish",
202
- "text": "Publish"
203
  },
204
  {
205
  "value_key": "delete",
206
- "text": "Delete"
207
  }
208
  ],
209
- "link_info": "https://icwp.io/a0",
210
- "link_blog": "https://icwp.io/wpsf21",
211
- "summary": "Restrict Access To Key WordPress Posts And Pages Actions",
212
- "description": "Careful: This will restrict access to page/post creation, editing and deletion."
213
  },
214
  {
215
- "key": "whitelabel_enable",
216
- "section": "section_whitelabel",
217
- "premium": true,
218
- "default": "N",
219
- "type": "checkbox",
220
- "link_info": "",
221
- "link_blog": "",
222
- "name": "Enable White Label",
223
- "summary": "Activate Your White Label Settings",
224
  "description": "Use this option to turn on/off the whole White Label feature."
225
  },
226
  {
227
- "key": "wl_hide_updates",
228
- "section": "section_whitelabel",
229
- "default": "Y",
230
- "type": "checkbox",
231
- "link_info": "",
232
- "link_blog": "",
233
- "name": "Hide Updates",
234
- "summary": "Hide Available Updates From Non Security Admins",
235
  "description": "Hides the availability of Shield updates from non-security admins."
236
  },
237
  {
238
- "key": "wl_pluginnamemain",
239
- "section": "section_whitelabel",
240
- "sensitive": true,
241
- "default": "Shield",
242
- "type": "text",
243
- "link_info": "",
244
- "link_blog": "",
245
- "name": "Plugin Name",
246
- "summary": "The Name Of The Plugin",
247
  "description": "The Name Of The Plugin."
248
  },
249
  {
250
- "key": "wl_namemenu",
251
- "section": "section_whitelabel",
252
- "sensitive": true,
253
- "default": "Shield Security",
254
- "type": "text",
255
- "link_info": "",
256
- "link_blog": "",
257
- "name": "Menu Title",
258
- "summary": "The Main Menu Title Of The Plugin",
259
  "description": "The Main Menu Title Of The Plugin. If left empty, the Plugin Name will be used."
260
  },
261
  {
262
- "key": "wl_companyname",
263
- "section": "section_whitelabel",
264
- "sensitive": true,
265
- "default": "One Dollar Plugin",
266
- "type": "text",
267
- "link_info": "",
268
- "link_blog": "",
269
- "name": "Company Name",
270
- "summary": "The Name Of Your Company",
271
  "description": "Provide the name of your company."
272
  },
273
  {
274
- "key": "wl_description",
275
- "section": "section_whitelabel",
276
- "sensitive": true,
277
- "default": "Secure Your Sites With The World's Most Powerful WordPress Security Plugin",
278
- "type": "text",
279
- "link_info": "",
280
- "link_blog": "",
281
- "name": "Plugin Tag Line",
282
- "summary": "The Tag Line Of The Plugin",
283
  "description": "The Tag Line Of The Plugin."
284
  },
285
  {
286
- "key": "wl_homeurl",
287
- "section": "section_whitelabel",
288
- "sensitive": true,
289
- "default": "https://icwp.io/7f",
290
- "type": "text",
291
- "link_info": "",
292
- "link_blog": "",
293
- "name": "Home URL",
294
- "summary": "Plugin Home Page URL",
295
  "description": "When a user clicks the home link for this plugin, this is where they'll be directed."
296
  },
297
  {
298
- "key": "wl_menuiconurl",
299
- "section": "section_whitelabel",
300
- "sensitive": true,
301
- "default": "",
302
- "type": "text",
303
- "link_info": "",
304
- "link_blog": "",
305
- "name": "Menu Icon",
306
- "summary": "Menu Icon URL",
307
  "description": "The URL of the icon displayed in the menu."
308
  },
309
  {
310
- "key": "wl_dashboardlogourl",
311
- "section": "section_whitelabel",
312
- "sensitive": true,
313
- "default": "",
314
- "type": "text",
315
- "link_info": "",
316
- "link_blog": "",
317
- "name": "Dashboard Logo",
318
- "summary": "Dashboard Logo URL",
 
 
 
 
 
 
 
 
 
 
 
 
319
  "description": "The URL of the logo displayed in the main dashboard. Should be 128x128px"
320
  }
321
  ],
322
- "definitions": {
323
- "help_video_id": "214855538",
324
  "admin_access_options_to_restrict": {
325
  "wpms_options": [
326
  "admin_email",
327
  "site_name",
328
  "registration"
329
  ],
330
- "wpms_pages": [
331
  "settings.php"
332
  ],
333
- "wp_options": [
334
  "blogname",
335
  "blogdescription",
336
  "siteurl",
@@ -341,7 +356,7 @@
341
  "comment_moderation",
342
  "blog_public"
343
  ],
344
- "wp_pages": [
345
  "options-general.php",
346
  "options-discussion.php",
347
  "options-reading.php",
1
  {
2
+ "slug": "admin_access_restriction",
3
+ "properties": {
4
+ "slug": "admin_access_restriction",
5
+ "name": "Security Admin",
6
  "show_module_menu_item": true,
7
+ "storage_key": "admin_access_restriction",
8
+ "tagline": "Protect your Security Plugin, not just your WordPress site",
9
+ "menu_title": "Security Admin",
10
+ "show_central": true,
11
+ "access_restricted": true,
12
+ "premium": false,
13
+ "run_if_whitelisted": false,
14
+ "run_if_verified_bot": true,
15
+ "order": 20
16
  },
17
  "admin_notices": {
18
  "certain-options-restricted": {
19
+ "id": "certain-options-restricted",
20
+ "schedule": "conditions",
21
  "valid_admin": true,
22
+ "type": "warning"
23
  },
24
+ "admin-users-restricted": {
25
+ "id": "admin-users-restricted",
26
+ "schedule": "conditions",
27
  "valid_admin": true,
28
+ "can_dismiss": false,
29
+ "type": "warning"
30
  }
31
  },
32
+ "sections": [
33
  {
34
+ "slug": "section_admin_access_restriction_settings",
35
+ "primary": true,
36
+ "title": "Security Admin Restriction Settings",
37
  "title_short": "Security Admin Settings",
38
+ "summary": [
39
  "Purpose - Restrict access using a simple Access Key.",
40
  "Recommendation - Use of this feature is highly recommend."
41
  ]
42
  },
43
  {
44
+ "slug": "section_admin_access_restriction_areas",
45
+ "title": "Security Admin Restriction Zones",
46
  "title_short": "Access Restriction Zones",
47
+ "summary": [
48
  "Purpose - Restricts access to key WordPress areas for all users not authenticated with the Security Admin Access system.",
49
  "Recommendation - Use of this feature is highly recommend."
50
  ]
51
  },
52
  {
53
+ "slug": "section_whitelabel",
54
+ "title": "Shield White Label",
55
  "title_short": "White Label",
56
+ "summary": [
57
  "Purpose - Rename and re-brand the Shield Security plugin for your client site installations."
58
  ]
59
  },
60
  {
61
+ "slug": "section_enable_plugin_feature_admin_access_restriction",
62
+ "title": "Enable Module: WordPress Security Admin",
63
  "title_short": "Disable Module",
64
+ "summary": [
65
  "Purpose - Restricts access to this plugin preventing unauthorized changes to your security settings.",
66
  "Recommendation - Keep the Security Admin feature turned on.",
67
  "You need to also enter a new Access Key to enable this feature."
68
  ]
69
  },
70
  {
71
+ "slug": "section_non_ui",
72
  "hidden": true
73
  }
74
  ],
75
+ "options": [
76
  {
77
+ "key": "enable_admin_access_restriction",
78
+ "section": "section_enable_plugin_feature_admin_access_restriction",
79
+ "default": "Y",
80
+ "type": "checkbox",
81
+ "link_info": "https://icwp.io/40",
82
+ "link_blog": "https://icwp.io/wpsf02",
83
+ "name": "Enable Security Admin",
84
+ "summary": "Enforce Security Admin Access Restriction",
85
  "description": "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."
86
  },
87
  {
88
+ "key": "admin_access_key",
89
+ "section": "section_admin_access_restriction_settings",
90
+ "sensitive": true,
91
+ "default": "",
92
+ "type": "password",
93
+ "link_info": "https://icwp.io/42",
94
+ "link_blog": "",
95
+ "name": "Security Admin Access Key",
96
+ "summary": "Provide/Update Security Admin Access Key",
97
  "description": "Careful: If you forget this, you could potentially lock yourself out from using this plugin."
98
  },
99
  {
100
+ "key": "admin_access_timeout",
101
+ "section": "section_admin_access_restriction_settings",
102
+ "default": 30,
103
+ "type": "integer",
104
+ "min": 1,
105
+ "link_info": "https://icwp.io/41",
106
+ "link_blog": "",
107
+ "name": "Security Admin Timeout",
108
+ "summary": "Specify An Automatic Timeout Interval For Security Admin Access",
109
  "description": "This will automatically expire your Security Admin Session. Does not apply until you enter the access key again. Default: 60 minutes."
110
  },
111
  {
112
+ "key": "admin_access_restrict_options",
113
+ "section": "section_admin_access_restriction_areas",
114
+ "default": "Y",
115
+ "type": "checkbox",
116
+ "link_info": "https://icwp.io/a0",
117
+ "link_blog": "https://icwp.io/wpsf32",
118
+ "name": "Pages",
119
+ "summary": "Restrict Access To Key WordPress Posts And Pages Actions",
120
  "description": "Careful: This will restrict access to page/post creation, editing and deletion. Note: Selecting 'Edit' will also restrict all other options."
121
  },
122
  {
123
+ "key": "admin_access_restrict_admin_users",
124
+ "section": "section_admin_access_restriction_areas",
125
+ "default": "N",
126
+ "type": "checkbox",
127
+ "link_info": "https://icwp.io/a0",
128
+ "link_blog": "",
129
+ "name": "Admin Users",
130
+ "summary": "Restrict Access To Create/Delete/Modify Other Admin Users",
131
  "description": "Careful: This will restrict the ability of WordPress administrators from creating, modifying or promoting other administrators."
132
  },
133
  {
134
+ "key": "admin_access_restrict_plugins",
135
+ "section": "section_admin_access_restriction_areas",
136
+ "type": "multiple_select",
137
+ "default": null,
138
  "value_options": [
139
  {
140
  "value_key": "activate_plugins",
141
+ "text": "Activate"
142
  },
143
  {
144
  "value_key": "install_plugins",
145
+ "text": "Install"
146
  },
147
  {
148
  "value_key": "update_plugins",
149
+ "text": "Update"
150
  },
151
  {
152
  "value_key": "delete_plugins",
153
+ "text": "Delete"
154
  }
155
  ],
156
+ "link_info": "https://icwp.io/a0",
157
+ "link_blog": "https://icwp.io/wpsf21",
158
+ "summary": "Restrict Access To Key WordPress Plugin Actions",
159
+ "description": "Careful: This will restrict access to plugin installation, update, activation and deletion. Note: Selecting 'Activate' will also restrict all other options."
160
  },
161
  {
162
+ "key": "admin_access_restrict_themes",
163
+ "section": "section_admin_access_restriction_areas",
164
+ "type": "multiple_select",
165
+ "default": null,
166
  "value_options": [
167
  {
168
  "value_key": "switch_themes",
169
+ "text": "Activate"
170
  },
171
  {
172
  "value_key": "edit_theme_options",
173
+ "text": "Edit Theme Options"
174
  },
175
  {
176
  "value_key": "install_themes",
177
+ "text": "Install"
178
  },
179
  {
180
  "value_key": "update_themes",
181
+ "text": "Update"
182
  },
183
  {
184
  "value_key": "delete_themes",
185
+ "text": "Delete"
186
  }
187
  ],
188
+ "link_info": "https://icwp.io/a0",
189
+ "link_blog": "https://icwp.io/wpsf21",
190
+ "summary": "Restrict Access To WordPress Theme Actions",
191
+ "description": "Careful: This will restrict access to theme installation, update, activation and deletion."
192
  },
193
  {
194
+ "key": "admin_access_restrict_posts",
195
+ "section": "section_admin_access_restriction_areas",
196
+ "type": "multiple_select",
197
+ "default": null,
198
  "value_options": [
199
  {
200
  "value_key": "edit",
201
+ "text": "Create / Edit"
202
  },
203
  {
204
  "value_key": "publish",
205
+ "text": "Publish"
206
  },
207
  {
208
  "value_key": "delete",
209
+ "text": "Delete"
210
  }
211
  ],
212
+ "link_info": "https://icwp.io/a0",
213
+ "link_blog": "https://icwp.io/wpsf21",
214
+ "summary": "Restrict Access To Key WordPress Posts And Pages Actions",
215
+ "description": "Careful: This will restrict access to page/post creation, editing and deletion."
216
  },
217
  {
218
+ "key": "whitelabel_enable",
219
+ "section": "section_whitelabel",
220
+ "premium": true,
221
+ "default": "N",
222
+ "type": "checkbox",
223
+ "link_info": "",
224
+ "link_blog": "",
225
+ "name": "Enable White Label",
226
+ "summary": "Activate Your White Label Settings",
227
  "description": "Use this option to turn on/off the whole White Label feature."
228
  },
229
  {
230
+ "key": "wl_hide_updates",
231
+ "section": "section_whitelabel",
232
+ "default": "Y",
233
+ "type": "checkbox",
234
+ "link_info": "",
235
+ "link_blog": "",
236
+ "name": "Hide Updates",
237
+ "summary": "Hide Available Updates From Non Security Admins",
238
  "description": "Hides the availability of Shield updates from non-security admins."
239
  },
240
  {
241
+ "key": "wl_pluginnamemain",
242
+ "section": "section_whitelabel",
243
+ "sensitive": true,
244
+ "default": "Shield",
245
+ "type": "text",
246
+ "link_info": "",
247
+ "link_blog": "",
248
+ "name": "Plugin Name",
249
+ "summary": "The Name Of The Plugin",
250
  "description": "The Name Of The Plugin."
251
  },
252
  {
253
+ "key": "wl_namemenu",
254
+ "section": "section_whitelabel",
255
+ "sensitive": true,
256
+ "default": "Shield Security",
257
+ "type": "text",
258
+ "link_info": "",
259
+ "link_blog": "",
260
+ "name": "Menu Title",
261
+ "summary": "The Main Menu Title Of The Plugin",
262
  "description": "The Main Menu Title Of The Plugin. If left empty, the Plugin Name will be used."
263
  },
264
  {
265
+ "key": "wl_companyname",
266
+ "section": "section_whitelabel",
267
+ "sensitive": true,
268
+ "default": "One Dollar Plugin",
269
+ "type": "text",
270
+ "link_info": "",
271
+ "link_blog": "",
272
+ "name": "Company Name",
273
+ "summary": "The Name Of Your Company",
274
  "description": "Provide the name of your company."
275
  },
276
  {
277
+ "key": "wl_description",
278
+ "section": "section_whitelabel",
279
+ "sensitive": true,
280
+ "default": "Secure Your Sites With The World's Most Powerful WordPress Security Plugin",
281
+ "type": "text",
282
+ "link_info": "",
283
+ "link_blog": "",
284
+ "name": "Plugin Tag Line",
285
+ "summary": "The Tag Line Of The Plugin",
286
  "description": "The Tag Line Of The Plugin."
287
  },
288
  {
289
+ "key": "wl_homeurl",
290
+ "section": "section_whitelabel",
291
+ "sensitive": true,
292
+ "default": "https://icwp.io/7f",
293
+ "type": "text",
294
+ "link_info": "",
295
+ "link_blog": "",
296
+ "name": "Home URL",
297
+ "summary": "Plugin Home Page URL",
298
  "description": "When a user clicks the home link for this plugin, this is where they'll be directed."
299
  },
300
  {
301
+ "key": "wl_menuiconurl",
302
+ "section": "section_whitelabel",
303
+ "sensitive": true,
304
+ "default": "pluginlogo_16x16.png",
305
+ "type": "text",
306
+ "link_info": "",
307
+ "link_blog": "",
308
+ "name": "Menu Icon",
309
+ "summary": "Menu Icon URL",
310
  "description": "The URL of the icon displayed in the menu."
311
  },
312
  {
313
+ "key": "wl_dashboardlogourl",
314
+ "section": "section_whitelabel",
315
+ "sensitive": true,
316
+ "default": "pluginlogo_128x128.png",
317
+ "type": "text",
318
+ "link_info": "",
319
+ "link_blog": "",
320
+ "name": "Dashboard Logo",
321
+ "summary": "Dashboard Logo URL",
322
+ "description": "The URL of the logo displayed in the main dashboard. Should be 128x128px"
323
+ },
324
+ {
325
+ "key": "wl_login2fa_logourl",
326
+ "section": "section_whitelabel",
327
+ "sensitive": true,
328
+ "default": "pluginlogo_banner-772x250.png",
329
+ "type": "text",
330
+ "link_info": "",
331
+ "link_blog": "",
332
+ "name": "Dashboard Logo",
333
+ "summary": "Dashboard Logo URL",
334
  "description": "The URL of the logo displayed in the main dashboard. Should be 128x128px"
335
  }
336
  ],
337
+ "definitions": {
338
+ "help_video_id": "214855538",
339
  "admin_access_options_to_restrict": {
340
  "wpms_options": [
341
  "admin_email",
342
  "site_name",
343
  "registration"
344
  ],
345
+ "wpms_pages": [
346
  "settings.php"
347
  ],
348
+ "wp_options": [
349
  "blogname",
350
  "blogdescription",
351
  "siteurl",
356
  "comment_moderation",
357
  "blog_public"
358
  ],
359
+ "wp_pages": [
360
  "options-general.php",
361
  "options-discussion.php",
362
  "options-reading.php",
src/config/feature-audit_trail.php CHANGED
@@ -1,173 +1,173 @@
1
  {
2
- "slug": "audit_trail",
3
- "properties": {
4
- "slug": "audit_trail",
5
- "name": "Audit Trail",
6
  "show_module_menu_item": true,
7
- "storage_key": "audit_trail",
8
- "tagline": "Get a view on what happens on your site, when it happens",
9
- "show_central": true,
10
- "access_restricted": true,
11
- "premium": false,
12
- "has_custom_actions": true,
13
- "order": 110
 
 
14
  },
15
- "sections": [
16
  {
17
- "slug": "section_audit_trail_options",
18
- "primary": true,
19
- "title": "Audit Trail Options",
20
  "title_short": "Options",
21
- "summary": [
22
  "Purpose - Provides finer control over the audit trail itself.",
23
  "Recommendation - These settings are dependent on your requirements."
24
  ]
25
  },
26
  {
27
- "slug": "section_enable_audit_contexts",
28
- "title": "Enable Audit Contexts",
29
  "title_short": "Audit Contexts",
30
- "summary":
31
- [
32
  "Purpose - Specify which types of actions on your site are logged.",
33
  "Recommendation - These settings are dependent on your requirements."
34
  ]
35
  },
36
  {
37
- "slug": "section_enable_plugin_feature_audit_trail",
38
- "title": "Enable Module: Audit Trail",
39
  "title_short": "Disable Module",
40
- "summary": [
41
  "Purpose - The Audit Trail is designed so you can look back on events and analyse what happened and what may have gone wrong.",
42
  "Recommendation - Keep the Audit Trail feature turned on."
43
  ]
44
  },
45
  {
46
- "slug": "section_non_ui",
47
  "hidden": true
48
  }
49
  ],
50
- "options": [
51
  {
52
- "key": "enable_audit_trail",
53
- "section": "section_enable_plugin_feature_audit_trail",
54
- "default": "Y",
55
- "type": "checkbox",
56
- "link_info": "https://icwp.io/5p",
57
- "link_blog": "https://icwp.io/a1",
58
- "name": "Enable Audit Trail",
59
- "summary": "Enable (or Disable) The Audit Trail module",
60
  "description": "Un-Checking this option will completely disable the Audit Trail module"
61
-
62
  },
63
  {
64
- "key": "audit_trail_auto_clean",
65
- "section": "section_audit_trail_options",
66
- "default": 14,
67
- "min": 1,
68
- "type": "integer",
69
- "link_info": "https://icwp.io/a2",
70
- "link_blog": "https://icwp.io/a1",
71
- "name": "Auto Clean",
72
- "summary": "Enable Audit Auto Cleaning",
73
  "description": "Events older than the number of days specified will be automatically cleaned from the database"
74
  },
75
  {
76
- "key": "audit_trail_max_entries",
77
- "section": "section_audit_trail_options",
78
- "premium": true,
79
- "default": 1000,
80
- "min": 0,
81
- "type": "integer",
82
- "link_info": "",
83
- "link_blog": "",
84
- "name": "Max Trail Length",
85
- "summary": "Maximum Audit Trail Length To Keep",
86
  "description": "Automatically remove any audit trail entries when this limit is exceeded."
87
  },
88
  {
89
- "key": "enable_audit_context_users",
90
- "section": "section_enable_audit_contexts",
91
- "default": "Y",
92
- "type": "checkbox",
93
- "link_info": "https://icwp.io/a3",
94
- "link_blog": "https://icwp.io/a1",
95
- "name": "Users And Logins",
96
- "summary": "Enable Audit Context - Users And Logins",
97
  "description": "When this context is enabled, the audit trail will track activity relating to: Users And Logins"
98
  },
99
  {
100
- "key": "enable_audit_context_plugins",
101
- "section": "section_enable_audit_contexts",
102
- "default": "Y",
103
- "type": "checkbox",
104
- "link_info": "https://icwp.io/a3",
105
- "link_blog": "https://icwp.io/a1",
106
- "name": "Plugins",
107
- "summary": "Enable Audit Context - Plugins",
108
  "description": "When this context is enabled, the audit trail will track activity relating to: WordPress Plugins"
109
  },
110
  {
111
- "key": "enable_audit_context_themes",
112
- "section": "section_enable_audit_contexts",
113
- "default": "Y",
114
- "type": "checkbox",
115
- "link_info": "https://icwp.io/a3",
116
- "link_blog": "https://icwp.io/a1",
117
- "name": "Themes",
118
- "summary": "Enable Audit Context - Themes",
119
  "description": "When this context is enabled, the audit trail will track activity relating to: WordPress Themes"
120
  },
121
  {
122
- "key": "enable_audit_context_posts",
123
- "section": "section_enable_audit_contexts",
124
- "default": "Y",
125
- "type": "checkbox",
126
- "link_info": "https://icwp.io/a3",
127
- "link_blog": "https://icwp.io/a1",
128
- "name": "Posts And Pages",
129
- "summary": "Enable Audit Context - Posts And Pages",
130
  "description": "When this context is enabled, the audit trail will track activity relating to: Editing and publishing of posts and pages"
131
  },
132
  {
133
- "key": "enable_audit_context_wordpress",
134
- "section": "section_enable_audit_contexts",
135
- "default": "Y",
136
- "type": "checkbox",
137
- "link_info": "https://icwp.io/a3",
138
- "link_blog": "https://icwp.io/a1",
139
- "name": "WordPress And Settings",
140
- "summary": "Enable Audit Context - WordPress And Settings",
141
  "description": "When this context is enabled, the audit trail will track activity relating to: WordPress upgrades and changes to particular WordPress settings"
142
  },
143
  {
144
- "key": "enable_audit_context_emails",
145
- "section": "section_enable_audit_contexts",
146
- "default": "Y",
147
- "type": "checkbox",
148
- "link_info": "https://icwp.io/a3",
149
- "link_blog": "https://icwp.io/a1",
150
- "name": "Emails",
151
- "summary": "Enable Audit Context - Emails",
152
  "description": "When this context is enabled, the audit trail will track activity relating to: Email Sending"
153
  },
154
  {
155
- "key": "enable_audit_context_wpsf",
156
- "section": "section_enable_audit_contexts",
157
- "default": "Y",
158
- "type": "checkbox",
159
- "link_info": "https://icwp.io/a4",
160
- "link_blog": "https://icwp.io/a1",
161
- "name": "Shield",
162
- "summary": "Enable Audit Context - Shield",
163
  "description": "When this context is enabled, the audit trail will track activity relating to: Shield"
164
  }
165
  ],
166
  "definitions": {
167
- "audit_trail_default_per_page": 25,
168
  "audit_trail_default_max_entries": 50,
169
- "audit_trail_table_name": "audit_trail",
170
- "audit_trail_table_columns": [
171
  "id",
172
  "rid",
173
  "wp_username",
1
  {
2
+ "slug": "audit_trail",
3
+ "properties": {
4
+ "slug": "audit_trail",
5
+ "name": "Audit Trail",
6
  "show_module_menu_item": true,
7
+ "storage_key": "audit_trail",
8
+ "tagline": "Get a view on what happens on your site, when it happens",
9
+ "show_central": true,
10
+ "access_restricted": true,
11
+ "premium": false,
12
+ "has_custom_actions": true,
13
+ "run_if_whitelisted": true,
14
+ "run_if_verified_bot": false,
15
+ "order": 110
16
  },
17
+ "sections": [
18
  {
19
+ "slug": "section_audit_trail_options",
20
+ "primary": true,
21
+ "title": "Audit Trail Options",
22
  "title_short": "Options",
23
+ "summary": [
24
  "Purpose - Provides finer control over the audit trail itself.",
25
  "Recommendation - These settings are dependent on your requirements."
26
  ]
27
  },
28
  {
29
+ "slug": "section_enable_audit_contexts",
30
+ "title": "Enable Audit Contexts",
31
  "title_short": "Audit Contexts",
32
+ "summary": [
 
33
  "Purpose - Specify which types of actions on your site are logged.",
34
  "Recommendation - These settings are dependent on your requirements."
35
  ]
36
  },
37
  {
38
+ "slug": "section_enable_plugin_feature_audit_trail",
39
+ "title": "Enable Module: Audit Trail",
40
  "title_short": "Disable Module",
41
+ "summary": [
42
  "Purpose - The Audit Trail is designed so you can look back on events and analyse what happened and what may have gone wrong.",
43
  "Recommendation - Keep the Audit Trail feature turned on."
44
  ]
45
  },
46
  {
47
+ "slug": "section_non_ui",
48
  "hidden": true
49
  }
50
  ],
51
+ "options": [
52
  {
53
+ "key": "enable_audit_trail",
54
+ "section": "section_enable_plugin_feature_audit_trail",
55
+ "default": "Y",
56
+ "type": "checkbox",
57
+ "link_info": "https://icwp.io/5p",
58
+ "link_blog": "https://icwp.io/a1",
59
+ "name": "Enable Audit Trail",
60
+ "summary": "Enable (or Disable) The Audit Trail module",
61
  "description": "Un-Checking this option will completely disable the Audit Trail module"
 
62
  },
63
  {
64
+ "key": "audit_trail_auto_clean",
65
+ "section": "section_audit_trail_options",
66
+ "default": 14,
67
+ "min": 1,
68
+ "type": "integer",
69
+ "link_info": "https://icwp.io/a2",
70
+ "link_blog": "https://icwp.io/a1",
71
+ "name": "Auto Clean",
72
+ "summary": "Enable Audit Auto Cleaning",
73
  "description": "Events older than the number of days specified will be automatically cleaned from the database"
74
  },
75
  {
76
+ "key": "audit_trail_max_entries",
77
+ "section": "section_audit_trail_options",
78
+ "premium": true,
79
+ "default": 1000,
80
+ "min": 0,
81
+ "type": "integer",
82
+ "link_info": "",
83
+ "link_blog": "",
84
+ "name": "Max Trail Length",
85
+ "summary": "Maximum Audit Trail Length To Keep",
86
  "description": "Automatically remove any audit trail entries when this limit is exceeded."
87
  },
88
  {
89
+ "key": "enable_audit_context_users",
90
+ "section": "section_enable_audit_contexts",
91
+ "default": "Y",
92
+ "type": "checkbox",
93
+ "link_info": "https://icwp.io/a3",
94
+ "link_blog": "https://icwp.io/a1",
95
+ "name": "Users And Logins",
96
+ "summary": "Enable Audit Context - Users And Logins",
97
  "description": "When this context is enabled, the audit trail will track activity relating to: Users And Logins"
98
  },
99
  {
100
+ "key": "enable_audit_context_plugins",
101
+ "section": "section_enable_audit_contexts",
102
+ "default": "Y",
103
+ "type": "checkbox",
104
+ "link_info": "https://icwp.io/a3",
105
+ "link_blog": "https://icwp.io/a1",
106
+ "name": "Plugins",
107
+ "summary": "Enable Audit Context - Plugins",
108
  "description": "When this context is enabled, the audit trail will track activity relating to: WordPress Plugins"
109
  },
110
  {
111
+ "key": "enable_audit_context_themes",
112
+ "section": "section_enable_audit_contexts",
113
+ "default": "Y",
114
+ "type": "checkbox",
115
+ "link_info": "https://icwp.io/a3",
116
+ "link_blog": "https://icwp.io/a1",
117
+ "name": "Themes",
118
+ "summary": "Enable Audit Context - Themes",
119
  "description": "When this context is enabled, the audit trail will track activity relating to: WordPress Themes"
120
  },
121
  {
122
+ "key": "enable_audit_context_posts",
123
+ "section": "section_enable_audit_contexts",
124
+ "default": "Y",
125
+ "type": "checkbox",
126
+ "link_info": "https://icwp.io/a3",
127
+ "link_blog": "https://icwp.io/a1",
128
+ "name": "Posts And Pages",
129
+ "summary": "Enable Audit Context - Posts And Pages",
130
  "description": "When this context is enabled, the audit trail will track activity relating to: Editing and publishing of posts and pages"
131
  },
132
  {
133
+ "key": "enable_audit_context_wordpress",
134
+ "section": "section_enable_audit_contexts",
135
+ "default": "Y",
136
+ "type": "checkbox",
137
+ "link_info": "https://icwp.io/a3",
138
+ "link_blog": "https://icwp.io/a1",
139
+ "name": "WordPress And Settings",
140
+ "summary": "Enable Audit Context - WordPress And Settings",
141
  "description": "When this context is enabled, the audit trail will track activity relating to: WordPress upgrades and changes to particular WordPress settings"
142
  },
143
  {
144
+ "key": "enable_audit_context_emails",
145
+ "section": "section_enable_audit_contexts",
146
+ "default": "Y",
147
+ "type": "checkbox",
148
+ "link_info": "https://icwp.io/a3",
149
+ "link_blog": "https://icwp.io/a1",
150
+ "name": "Emails",
151
+ "summary": "Enable Audit Context - Emails",
152
  "description": "When this context is enabled, the audit trail will track activity relating to: Email Sending"
153
  },
154
  {
155
+ "key": "enable_audit_context_wpsf",
156
+ "section": "section_enable_audit_contexts",
157
+ "default": "Y",
158
+ "type": "checkbox",
159
+ "link_info": "https://icwp.io/a4",
160
+ "link_blog": "https://icwp.io/a1",
161
+ "name": "Shield",
162
+ "summary": "Enable Audit Context - Shield",
163
  "description": "When this context is enabled, the audit trail will track activity relating to: Shield"
164
  }
165
  ],
166
  "definitions": {
167
+ "audit_trail_default_per_page": 25,
168
  "audit_trail_default_max_entries": 50,
169
+ "audit_trail_table_name": "audit_trail",
170
+ "audit_trail_table_columns": [
171
  "id",
172
  "rid",
173
  "wp_username",
src/config/feature-autoupdates.php CHANGED
@@ -9,7 +9,8 @@
9
  "show_central": true,
10
  "access_restricted": true,
11
  "premium": false,
12
- "whitelist_exempt": true,
 
13
  "order": 60
14
  },
15
  "sections": [
9
  "show_central": true,
10
  "access_restricted": true,
11
  "premium": false,
12
+ "run_if_whitelisted": true,
13
+ "run_if_verified_bot": true,
14
  "order": 60
15
  },
16
  "sections": [
src/config/feature-comments_filter.php CHANGED
@@ -1,162 +1,160 @@
1
  {
2
- "slug": "comments_filter",
3
- "properties": {
4
- "slug": "comments_filter",
5
- "name": "Comments SPAM",
6
  "show_module_menu_item": true,
7
- "storage_key": "commentsfilter",
8
- "tagline": "Block comment SPAM and retain your privacy",
9
- "use_sessions": true,
10
- "show_central": true,
11
- "access_restricted": true,
12
- "premium": false,
13
- "order": 50
 
 
14
  },
15
  "admin_notices": {
16
  "akismet-running": {
17
- "id": "akismet-running",
18
- "schedule": "conditions",
19
  "valid_admin": true,
20
- "type": "warning"
21
  }
22
  },
23
- "sections": [
24
  {
25
- "slug": "section_bot_comment_spam_protection_filter",
26
- "primary": true,
27
- "title": "Automatic Bot Comment SPAM Protection Filter",
28
  "title_short": "Bot SPAM",
29
- "summary":
30
- [
31
  "Purpose - Blocks 100% of all automated bot-generated comment SPAM.",
32
  "Recommendation - Use of this feature is highly recommend."
33
  ]
34
  },
35
  {
36
- "slug": "section_recaptcha",
37
- "title": "Google reCAPTCHA",
38
  "title_short": "reCAPTCHA",
39
- "summary": [
40
  "Purpose - Adds Google reCAPTCHA to the Comment Forms.",
41
  "Recommendation - Keep this turned on.",
42
  "Note - You will need to register for Google reCAPTCHA keys and store them in the Shield 'Dashboard' settings."
43
  ]
44
  },
45
  {
46
- "slug": "section_human_spam_filter",
47
- "title": "Human Comment SPAM Protection Filter",
48
  "title_short": "Human SPAM",
49
- "summary":
50
- [
51
  "Purpose - Uses a 3rd party SPAM dictionary to detect human-based comment SPAM.",
52
  "Recommendation - Use of this feature is highly recommend.This tool, unlike other SPAM tools such as Akismet, will not send your comment data to 3rd party services for analysis."
53
  ]
54
  },
55
  {
56
- "slug": "section_user_messages",
57
- "title": "Customize Messages Shown To User",
58
  "title_short": "Visitor Messages",
59
- "summary":
60
- [
61
  "Purpose - Customize the messages shown to visitors.",
62
  "Recommendation - Be sure to change the messages to suit your audience.",
63
  "Hint - To reset any message to its default, enter the text exactly: default"
64
  ]
65
  },
66
  {
67
- "slug": "section_enable_plugin_feature_spam_comments_protection_filter",
68
- "title": "Enable Module: Comments SPAM Protection",
69
  "title_short": "Disable Module",
70
- "summary":
71
- [
72
  "Purpose - The Comments Filter can block 100% of automated spam bots and also offer the option to analyse human-generated spam.",
73
  "Recommendation - Keep the Comments Filter feature turned on."
74
  ]
75
  },
76
  {
77
- "slug": "section_non_ui",
78
  "hidden": true
79
  }
80
  ],
81
- "options": [
82
  {
83
- "key": "enable_comments_filter",
84
- "section": "section_enable_plugin_feature_spam_comments_protection_filter",
85
- "default": "Y",
86
- "type": "checkbox",
87
- "link_info": "https://icwp.io/3z",
88
- "link_blog": "https://icwp.io/wpsf04",
89
- "name": "Enable SPAM Protection",
90
- "summary": "Enable (or Disable) The Comments SPAM Protection module",
91
  "description": "Un-Checking this option will completely disable the Comments SPAM Protection module"
92
  },
93
  {
94
- "key": "enable_comments_gasp_protection",
95
- "section": "section_bot_comment_spam_protection_filter",
96
- "default": "N",
97
- "type": "checkbox",
98
- "link_info": "https://icwp.io/3n",
99
- "link_blog": "https://icwp.io/2n",
100
- "name": "GASP Protection",
101
- "summary": "Block Bot Comment SPAM",
102
  "description": "Taking the lead from the original GASP plugin for WordPress, we have extended it to include advanced spam-bot protection."
103
  },
104
  {
105
- "key": "comments_cooldown_interval",
106
- "section": "section_bot_comment_spam_protection_filter",
107
- "default": 10,
108
- "type": "integer",
109
- "link_info": "https://icwp.io/3o",
110
- "link_blog": "",
111
- "name": "Comments Cooldown",
112
- "summary": "Limit posting comments to X seconds after the page has loaded",
113
  "description": "By forcing a comments cooldown period, you restrict a Spambot's ability to post multiple times to your posts."
114
  },
115
  {
116
- "key": "comments_default_action_spam_bot",
117
- "section": "section_bot_comment_spam_protection_filter",
118
- "default": "trash",
119
- "type": "select",
120
  "value_options": [
121
  {
122
  "value_key": 0,
123
- "text": "Mark As Pending Moderation"
124
  },
125
  {
126
  "value_key": "spam",
127
- "text": "Mark As SPAM"
128
  },
129
  {
130
  "value_key": "trash",
131
- "text": "Move To Trash"
132
  },
133
  {
134
  "value_key": "reject",
135
- "text": "Reject And Redirect"
136
  }
137
  ],
138
- "link_info": "https://icwp.io/6j",
139
- "link_blog": "",
140
- "name": "Default SPAM Action",
141
- "summary": "How To Categorise Comments When Identified To Be SPAM",
142
- "description": "When a comment is detected as being SPAM from an automatic bot, the comment will be categorised based on this setting."
143
  },
144
  {
145
- "key": "enable_comments_human_spam_filter",
146
- "section": "section_human_spam_filter",
147
- "default": "N",
148
- "type": "checkbox",
149
- "link_info": "https://icwp.io/57",
150
- "link_blog": "https://icwp.io/9w",
151
- "name": "Human SPAM Filter",
152
- "summary": "Enable (or Disable) The Human SPAM Filter module",
153
  "description": "Scans the content of WordPress comments for keywords that are indicative of SPAM and marks the comment according to your preferred setting below."
154
  },
155
  {
156
- "key": "enable_comments_human_spam_filter_items",
157
- "section": "section_human_spam_filter",
158
- "type": "multiple_select",
159
- "default": [
160
  "author_name",
161
  "author_email",
162
  "comment_content",
@@ -167,164 +165,164 @@
167
  "value_options": [
168
  {
169
  "value_key": "author_name",
170
- "text": "Author Name"
171
  },
172
  {
173
  "value_key": "author_email",
174
- "text": "Author Email"
175
  },
176
  {
177
  "value_key": "comment_content",
178
- "text": "Comment Content"
179
  },
180
  {
181
  "value_key": "url",
182
- "text": "URL"
183
  },
184
  {
185
  "value_key": "ip_address",
186
- "text": "IP Address"
187
  },
188
  {
189
  "value_key": "user_agent",
190
- "text": "Browser User Agent"
191
  }
192
  ],
193
- "link_info": "https://icwp.io/58",
194
- "link_blog": "",
195
- "name": "Comment Filter Items",
196
- "summary": "Select The Items To Scan For SPAM",
197
- "description": "When a user submits a comment, only the selected parts of the comment data will be scanned for SPAM content."
198
  },
199
  {
200
- "key": "comments_default_action_human_spam",
201
- "section": "section_human_spam_filter",
202
- "default": 0,
203
- "type": "select",
204
  "value_options": [
205
  {
206
  "value_key": 0,
207
- "text": "Mark As Pending Moderation"
208
  },
209
  {
210
  "value_key": "spam",
211
- "text": "Mark As SPAM"
212
  },
213
  {
214
  "value_key": "trash",
215
- "text": "Move To Trash"
216
  },
217
  {
218
  "value_key": "reject",
219
- "text": "Reject And Redirect"
220
  }
221
  ],
222
- "name": "Default SPAM Action",
223
- "summary": "How To Categorise Comments When Identified To Be SPAM'",
224
- "description": "When a comment is detected as being SPAM from a human commenter, the comment will be categorised based on this setting."
225
  },
226
  {
227
- "key": "enable_google_recaptcha_comments",
228
- "section": "section_recaptcha",
229
- "default": "N",
230
- "type": "checkbox",
231
- "link_info": "https://icwp.io/shld5",
232
- "link_blog": "",
233
- "name": "Google reCAPTCHA",
234
- "summary": "Enable Google reCAPTCHA For Comments",
235
  "description": "Use Google reCAPTCHA on the comments form to prevent bot-spam comments."
236
  },
237
  {
238
- "key": "google_recaptcha_style_comments",
239
- "section": "section_recaptcha",
240
- "premium": true,
241
- "default": "default",
242
- "type": "select",
243
  "value_options": [
244
  {
245
  "value_key": "default",
246
- "text": "Default"
247
  },
248
  {
249
  "value_key": "light",
250
- "text": "Light Theme"
251
  },
252
  {
253
  "value_key": "light",
254
- "text": "Light Theme"
255
  },
256
  {
257
  "value_key": "dark",
258
- "text": "Dark Theme"
259
  },
260
  {
261
  "value_key": "invisible",
262
- "text": "Invisible reCAPTCHA"
263
  }
264
  ],
265
- "link_info": "",
266
- "link_blog": "",
267
- "name": "reCAPTCHA Style",
268
- "summary": "How Google reCAPTCHA Will Be Displayed",
269
- "description": "You can choose the reCAPTCHA display format that best suits your site, including the new Invisible Recaptcha."
270
  },
271
  {
272
- "key": "comments_token_expire_interval",
273
- "section": "section_bot_comment_spam_protection_filter",
274
- "default": 600,
275
- "type": "integer",
276
- "link_info": "https://icwp.io/3o",
277
- "link_blog": "https://icwp.io/9v",
278
- "name": "Comment Token Expire",
279
- "summary": "A visitor has X seconds within which to post a comment",
280
  "description": "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."
281
  },
282
  {
283
- "key": "custom_message_checkbox",
284
- "section": "section_user_messages",
285
- "sensitive": true,
286
- "default": "default",
287
- "type": "text",
288
- "link_info": "https://icwp.io/3p",
289
- "link_blog": "",
290
- "name": "Custom Checkbox Message",
291
- "summary": "If you want a custom checkbox message, please provide this here",
292
  "description": "You can customise the message beside the checkbox."
293
  },
294
  {
295
- "key": "custom_message_alert",
296
- "section": "section_user_messages",
297
- "sensitive": true,
298
- "default": "default",
299
- "type": "text",
300
- "link_info": "https://icwp.io/3p",
301
- "link_blog": "",
302
- "name": "Custom Alert Message",
303
- "summary": "If you want a custom alert message, please provide this here",
304
  "description": "This alert message is displayed when a visitor attempts to submit a comment without checking the box."
305
  },
306
  {
307
- "key": "custom_message_comment_wait",
308
- "section": "section_user_messages",
309
- "sensitive": true,
310
- "default": "default",
311
- "type": "text",
312
- "link_info": "https://icwp.io/3p",
313
- "link_blog": "",
314
- "name": "Custom Wait Message",
315
- "summary": "If you want a custom submit-button wait message, please provide this here.",
316
  "description": "Where you see the '%s' this will be the number of seconds. You must ensure you include 1, and only 1, of these."
317
  },
318
  {
319
- "key": "custom_message_comment_reload",
320
- "section": "section_user_messages",
321
- "sensitive": true,
322
- "default": "default",
323
- "type": "text",
324
- "link_info": "https://icwp.io/3p",
325
- "link_blog": "",
326
- "name": "Custom Reload Message",
327
- "summary": "If you want a custom message when the comment token has expired, please provide this here.",
328
  "description": "This message is displayed on the submit-button when the comment token is expired."
329
  },
330
  {
@@ -334,8 +332,8 @@
334
  "default": 0
335
  }
336
  ],
337
- "definitions": {
338
- "spambot_comments_filter_table_name": "spambot_comments_filter",
339
  "spambot_comments_filter_table_columns": [
340
  "id",
341
  "post_id",
1
  {
2
+ "slug": "comments_filter",
3
+ "properties": {
4
+ "slug": "comments_filter",
5
+ "name": "Comments SPAM",
6
  "show_module_menu_item": true,
7
+ "storage_key": "commentsfilter",
8
+ "tagline": "Block comment SPAM and retain your privacy",
9
+ "use_sessions": true,
10
+ "show_central": true,
11
+ "access_restricted": true,
12
+ "premium": false,
13
+ "run_if_whitelisted": false,
14
+ "run_if_verified_bot": false,
15
+ "order": 50
16
  },
17
  "admin_notices": {
18
  "akismet-running": {
19
+ "id": "akismet-running",
20
+ "schedule": "conditions",
21
  "valid_admin": true,
22
+ "type": "warning"
23
  }
24
  },
25
+ "sections": [
26
  {
27
+ "slug": "section_bot_comment_spam_protection_filter",
28
+ "primary": true,
29
+ "title": "Automatic Bot Comment SPAM Protection Filter",
30
  "title_short": "Bot SPAM",
31
+ "summary": [
 
32
  "Purpose - Blocks 100% of all automated bot-generated comment SPAM.",
33
  "Recommendation - Use of this feature is highly recommend."
34
  ]
35
  },
36
  {
37
+ "slug": "section_recaptcha",
38
+ "title": "Google reCAPTCHA",
39
  "title_short": "reCAPTCHA",
40
+ "summary": [
41
  "Purpose - Adds Google reCAPTCHA to the Comment Forms.",
42
  "Recommendation - Keep this turned on.",
43
  "Note - You will need to register for Google reCAPTCHA keys and store them in the Shield 'Dashboard' settings."
44
  ]
45
  },
46
  {
47
+ "slug": "section_human_spam_filter",
48
+ "title": "Human Comment SPAM Protection Filter",
49
  "title_short": "Human SPAM",
50
+ "summary": [
 
51
  "Purpose - Uses a 3rd party SPAM dictionary to detect human-based comment SPAM.",
52
  "Recommendation - Use of this feature is highly recommend.This tool, unlike other SPAM tools such as Akismet, will not send your comment data to 3rd party services for analysis."
53
  ]
54
  },
55
  {
56
+ "slug": "section_user_messages",
57
+ "title": "Customize Messages Shown To User",
58
  "title_short": "Visitor Messages",
59
+ "summary": [
 
60
  "Purpose - Customize the messages shown to visitors.",
61
  "Recommendation - Be sure to change the messages to suit your audience.",
62
  "Hint - To reset any message to its default, enter the text exactly: default"
63
  ]
64
  },
65
  {
66
+ "slug": "section_enable_plugin_feature_spam_comments_protection_filter",
67
+ "title": "Enable Module: Comments SPAM Protection",
68
  "title_short": "Disable Module",
69
+ "summary": [
 
70
  "Purpose - The Comments Filter can block 100% of automated spam bots and also offer the option to analyse human-generated spam.",
71
  "Recommendation - Keep the Comments Filter feature turned on."
72
  ]
73
  },
74
  {
75
+ "slug": "section_non_ui",
76
  "hidden": true
77
  }
78
  ],
79
+ "options": [
80
  {
81
+ "key": "enable_comments_filter",
82
+ "section": "section_enable_plugin_feature_spam_comments_protection_filter",
83
+ "default": "Y",
84
+ "type": "checkbox",
85
+ "link_info": "https://icwp.io/3z",
86
+ "link_blog": "https://icwp.io/wpsf04",
87
+ "name": "Enable SPAM Protection",
88
+ "summary": "Enable (or Disable) The Comments SPAM Protection module",
89
  "description": "Un-Checking this option will completely disable the Comments SPAM Protection module"
90
  },
91
  {
92
+ "key": "enable_comments_gasp_protection",
93
+ "section": "section_bot_comment_spam_protection_filter",
94
+ "default": "N",
95
+ "type": "checkbox",
96
+ "link_info": "https://icwp.io/3n",
97
+ "link_blog": "https://icwp.io/2n",
98
+ "name": "GASP Protection",
99
+ "summary": "Block Bot Comment SPAM",
100
  "description": "Taking the lead from the original GASP plugin for WordPress, we have extended it to include advanced spam-bot protection."
101
  },
102
  {
103
+ "key": "comments_cooldown_interval",
104
+ "section": "section_bot_comment_spam_protection_filter",
105
+ "default": 10,
106
+ "type": "integer",
107
+ "link_info": "https://icwp.io/3o",
108
+ "link_blog": "",
109
+ "name": "Comments Cooldown",
110
+ "summary": "Limit posting comments to X seconds after the page has loaded",
111
  "description": "By forcing a comments cooldown period, you restrict a Spambot's ability to post multiple times to your posts."
112
  },
113
  {
114
+ "key": "comments_default_action_spam_bot",
115
+ "section": "section_bot_comment_spam_protection_filter",
116
+ "default": "trash",
117
+ "type": "select",
118
  "value_options": [
119
  {
120
  "value_key": 0,
121
+ "text": "Mark As Pending Moderation"
122
  },
123
  {
124
  "value_key": "spam",
125
+ "text": "Mark As SPAM"
126
  },
127
  {
128
  "value_key": "trash",
129
+ "text": "Move To Trash"
130
  },
131
  {
132
  "value_key": "reject",
133
+ "text": "Reject And Redirect"
134
  }
135
  ],
136
+ "link_info": "https://icwp.io/6j",
137
+ "link_blog": "",
138
+ "name": "Default SPAM Action",
139
+ "summary": "How To Categorise Comments When Identified To Be SPAM",
140
+ "description": "When a comment is detected as being SPAM from an automatic bot, the comment will be categorised based on this setting."
141
  },
142
  {
143
+ "key": "enable_comments_human_spam_filter",
144
+ "section": "section_human_spam_filter",
145
+ "default": "N",
146
+ "type": "checkbox",
147
+ "link_info": "https://icwp.io/57",
148
+ "link_blog": "https://icwp.io/9w",
149
+ "name": "Human SPAM Filter",
150
+ "summary": "Enable (or Disable) The Human SPAM Filter module",
151
  "description": "Scans the content of WordPress comments for keywords that are indicative of SPAM and marks the comment according to your preferred setting below."
152
  },
153
  {
154
+ "key": "enable_comments_human_spam_filter_items",
155
+ "section": "section_human_spam_filter",
156
+ "type": "multiple_select",
157
+ "default": [
158
  "author_name",
159
  "author_email",
160
  "comment_content",
165
  "value_options": [
166
  {
167
  "value_key": "author_name",
168
+ "text": "Author Name"
169
  },
170
  {
171
  "value_key": "author_email",
172
+ "text": "Author Email"
173
  },
174
  {
175
  "value_key": "comment_content",
176
+ "text": "Comment Content"
177
  },
178
  {
179
  "value_key": "url",
180
+ "text": "URL"
181
  },
182
  {
183
  "value_key": "ip_address",
184
+ "text": "IP Address"
185
  },
186
  {
187
  "value_key": "user_agent",
188
+ "text": "Browser User Agent"
189
  }
190
  ],
191
+ "link_info": "https://icwp.io/58",
192
+ "link_blog": "",
193
+ "name": "Comment Filter Items",
194
+ "summary": "Select The Items To Scan For SPAM",
195
+ "description": "When a user submits a comment, only the selected parts of the comment data will be scanned for SPAM content."
196
  },
197
  {
198
+ "key": "comments_default_action_human_spam",
199
+ "section": "section_human_spam_filter",
200
+ "default": 0,
201
+ "type": "select",
202
  "value_options": [
203
  {
204
  "value_key": 0,
205
+ "text": "Mark As Pending Moderation"
206
  },
207
  {
208
  "value_key": "spam",
209
+ "text": "Mark As SPAM"
210
  },
211
  {
212
  "value_key": "trash",
213
+ "text": "Move To Trash"
214
  },
215
  {
216
  "value_key": "reject",
217
+ "text": "Reject And Redirect"
218
  }
219
  ],
220
+ "name": "Default SPAM Action",
221
+ "summary": "How To Categorise Comments When Identified To Be SPAM'",
222
+ "description": "When a comment is detected as being SPAM from a human commenter, the comment will be categorised based on this setting."
223
  },
224
  {
225
+ "key": "enable_google_recaptcha_comments",
226
+ "section": "section_recaptcha",
227
+ "default": "N",
228
+ "type": "checkbox",
229
+ "link_info": "https://icwp.io/shld5",
230
+ "link_blog": "",
231
+ "name": "Google reCAPTCHA",
232
+ "summary": "Enable Google reCAPTCHA For Comments",
233
  "description": "Use Google reCAPTCHA on the comments form to prevent bot-spam comments."
234
  },
235
  {
236
+ "key": "google_recaptcha_style_comments",
237
+ "section": "section_recaptcha",
238
+ "premium": true,
239
+ "default": "default",
240
+ "type": "select",
241
  "value_options": [
242
  {
243
  "value_key": "default",
244
+ "text": "Default"
245
  },
246
  {
247
  "value_key": "light",
248
+ "text": "Light Theme"
249
  },
250
  {
251
  "value_key": "light",
252
+ "text": "Light Theme"
253
  },
254
  {
255
  "value_key": "dark",
256
+ "text": "Dark Theme"
257
  },
258
  {
259
  "value_key": "invisible",
260
+ "text": "Invisible reCAPTCHA"
261
  }
262
  ],
263
+ "link_info": "",
264
+ "link_blog": "",
265
+ "name": "reCAPTCHA Style",
266
+ "summary": "How Google reCAPTCHA Will Be Displayed",
267
+ "description": "You can choose the reCAPTCHA display format that best suits your site, including the new Invisible Recaptcha."
268
  },
269
  {
270
+ "key": "comments_token_expire_interval",
271
+ "section": "section_bot_comment_spam_protection_filter",
272
+ "default": 600,
273
+ "type": "integer",
274
+ "link_info": "https://icwp.io/3o",
275
+ "link_blog": "https://icwp.io/9v",
276
+ "name": "Comment Token Expire",
277
+ "summary": "A visitor has X seconds within which to post a comment",
278
  "description": "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."
279
  },
280
  {
281
+ "key": "custom_message_checkbox",
282
+ "section": "section_user_messages",
283
+ "sensitive": true,
284
+ "default": "default",
285
+ "type": "text",
286
+ "link_info": "https://icwp.io/3p",
287
+ "link_blog": "",
288
+ "name": "Custom Checkbox Message",
289
+ "summary": "If you want a custom checkbox message, please provide this here",
290
  "description": "You can customise the message beside the checkbox."
291
  },
292
  {
293
+ "key": "custom_message_alert",
294
+ "section": "section_user_messages",
295
+ "sensitive": true,
296
+ "default": "default",
297
+ "type": "text",
298
+ "link_info": "https://icwp.io/3p",
299
+ "link_blog": "",
300
+ "name": "Custom Alert Message",
301
+ "summary": "If you want a custom alert message, please provide this here",
302
  "description": "This alert message is displayed when a visitor attempts to submit a comment without checking the box."
303
  },
304
  {
305
+ "key": "custom_message_comment_wait",
306
+ "section": "section_user_messages",
307
+ "sensitive": true,
308
+ "default": "default",
309
+ "type": "text",
310
+ "link_info": "https://icwp.io/3p",
311
+ "link_blog": "",
312
+ "name": "Custom Wait Message",
313
+ "summary": "If you want a custom submit-button wait message, please provide this here.",
314
  "description": "Where you see the '%s' this will be the number of seconds. You must ensure you include 1, and only 1, of these."
315
  },
316
  {
317
+ "key": "custom_message_comment_reload",
318
+ "section": "section_user_messages",
319
+ "sensitive": true,
320
+ "default": "default",
321
+ "type": "text",
322
+ "link_info": "https://icwp.io/3p",
323
+ "link_blog": "",
324
+ "name": "Custom Reload Message",
325
+ "summary": "If you want a custom message when the comment token has expired, please provide this here.",
326
  "description": "This message is displayed on the submit-button when the comment token is expired."
327
  },
328
  {
332
  "default": 0
333
  }
334
  ],
335
+ "definitions": {
336
+ "spambot_comments_filter_table_name": "spambot_comments_filter",
337
  "spambot_comments_filter_table_columns": [
338
  "id",
339
  "post_id",
src/config/feature-email.php CHANGED
@@ -9,7 +9,7 @@
9
  "show_central": false,
10
  "premium": false,
11
  "access_restricted": true,
12
- "whitelist_exempt": true
13
  },
14
  "sections": [
15
  {
9
  "show_central": false,
10
  "premium": false,
11
  "access_restricted": true,
12
+ "run_if_whitelisted": true
13
  },
14
  "sections": [
15
  {
src/config/feature-firewall.php CHANGED
@@ -1,266 +1,267 @@
1
  {
2
- "slug": "firewall",
3
- "properties": {
4
- "slug": "firewall",
5
- "name": "Firewall",
6
  "show_module_menu_item": true,
7
- "storage_key": "firewall",
8
- "tagline": "Automatically block malicious URLs and data sent to your site",
9
- "show_central": true,
10
- "access_restricted": true,
11
- "premium": false,
12
- "order": 30
 
 
13
  },
14
- "sections": [
15
  {
16
- "slug": "section_firewall_blocking_options",
17
- "primary": true,
18
- "title": "Firewall Blocking Options",
19
  "title_short": "Firewall Blocking",
20
- "summary": [
21
  "Here you choose what kind of malicious data to scan for.",
22
  "Recommendation - Turn on as many options here as you can. If you find an incompatibility or something stops working, un-check 1 option at a time until you find the problem or review the Audit Trail."
23
  ]
24
  },
25
  {
26
- "slug": "section_choose_firewall_block_response",
27
- "title": "Choose Firewall Block Response",
28
  "title_short": "Firewall Response",
29
- "summary": [
30
  "Here you choose how the plugin will respond when it detects malicious data.",
31
  "Recommendation - Choose the option 'Die With Message'."
32
  ]
33
  },
34
  {
35
- "slug": "section_whitelist",
36
- "title": "Whitelists - IPs, Pages, Parameters, and Users that by-pass the Firewall",
37
  "title_short": "Whitelist",
38
- "summary": [
39
  "In principle you should not need to whitelist anything or anyone unless you have discovered a collision with another plugin.",
40
  "Recommendation - Do not whitelist anything unless you are confident in what you are doing."
41
  ]
42
  },
43
  {
44
- "slug": "section_user_messages",
45
- "title": "Customize Messages Shown To User",
46
  "title_short": "Visitor Messages",
47
- "summary":
48
- [
49
  "Purpose - Customize the messages shown to visitors.",
50
  "Recommendation - Be sure to change the messages to suit your audience.",
51
  "Hint - To reset any message to its default, enter the text exactly: default"
52
  ]
53
  },
54
  {
55
- "slug": "section_enable_plugin_feature_wordpress_firewall",
56
- "title": "Enable Module: Firewall",
57
  "title_short": "Disable Module",
58
- "summary": [
59
- "Purpose - The Firewall is designed to analyse data sent to your website and block any requests that appear to be malicious.",
60
- "Recommendation - Keep the Firewall feature turned on."
61
- ]
62
  },
63
  {
64
- "slug": "section_non_ui",
65
  "hidden": true
66
  }
67
  ],
68
- "options": [
69
  {
70
- "key": "enable_firewall",
71
- "section": "section_enable_plugin_feature_wordpress_firewall",
72
- "default": "Y",
73
- "type": "checkbox",
74
- "link_info": "https://icwp.io/43",
75
- "link_blog": "https://icwp.io/wpsf01",
76
- "name": "Enable Firewall",
77
- "summary": "Enable (or Disable) The Firewall module",
78
  "description": "Un-Checking this option will completely disable the Firewall module"
79
  },
80
  {
81
- "key": "include_cookie_checks",
82
- "section": "section_firewall_blocking_options",
83
- "default": "N",
84
- "type": "checkbox",
85
- "link_info": "",
86
- "link_blog": "",
87
- "name": "Include Cookies",
88
- "summary": "Also Test Cookie Values In Firewall Tests",
89
  "description": "The firewall tests GET and POST, but with this option checked it will also check COOKIE values."
90
  },
91
  {
92
- "key": "block_dir_traversal",
93
- "section": "section_firewall_blocking_options",
94
- "default": "Y",
95
- "type": "checkbox",
96
- "link_info": "",
97
- "link_blog": "",
98
- "name": "Directory Traversals",
99
- "summary": "Block Directory Traversals",
100
  "description": "This will block directory traversal paths in in application parameters."
101
  },
102
  {
103
- "key": "block_sql_queries",
104
- "section": "section_firewall_blocking_options",
105
- "default": "Y",
106
- "type": "checkbox",
107
- "link_info": "",
108
- "link_blog": "",
109
- "name": "SQL Queries",
110
- "summary": "Block SQL Queries",
111
  "description": "This will block SQL in application parameters."
112
  },
113
  {
114
- "key": "block_wordpress_terms",
115
- "section": "section_firewall_blocking_options",
116
- "default": "N",
117
- "type": "checkbox",
118
- "link_info": "",
119
- "link_blog": "",
120
- "name": "WordPress Terms",
121
- "summary": "Block WordPress Specific Terms",
122
  "description": "This will block WordPress specific terms in application parameters (wp_, user_login, etc.)."
123
  },
124
  {
125
- "key": "block_field_truncation",
126
- "section": "section_firewall_blocking_options",
127
- "default": "Y",
128
- "type": "checkbox",
129
- "link_info": "",
130
- "link_blog": "",
131
- "name": "Field Truncation",
132
- "summary": "Block Field Truncation Attacks",
133
  "description": "This will block field truncation attacks in application parameters"
134
  },
135
  {
136
- "key": "block_php_code",
137
- "section": "section_firewall_blocking_options",
138
- "default": "N",
139
- "type": "checkbox",
140
- "link_info": "",
141
- "link_blog": "",
142
- "name": "PHP Code",
143
- "summary": "Block PHP Code Includes",
144
  "description": "This will block any data that appears to try and include PHP files. Will probably block saving within the Plugin/Theme file editors."
145
  },
146
  {
147
- "key": "block_exe_file_uploads",
148
- "section": "section_firewall_blocking_options",
149
- "default": "N",
150
- "type": "checkbox",
151
- "link_info": "",
152
- "link_blog": "",
153
- "name": "Exe File Uploads",
154
- "summary": "Block Executable File Uploads",
155
  "description": "This will block executable file uploads (.php, .exe, etc.)."
156
  },
157
  {
158
- "key": "block_leading_schema",
159
- "section": "section_firewall_blocking_options",
160
- "default": "N",
161
- "type": "checkbox",
162
- "link_info": "",
163
- "link_blog": "",
164
- "name": "Leading Schemas",
165
- "summary": "Block Leading Schemas (HTTPS / HTTP)",
166
  "description": "This will block leading schemas http:// and https:// in application parameters (off by default; may cause problems with other plugins)."
167
  },
168
  {
169
- "key": "block_aggressive",
170
- "section": "section_firewall_blocking_options",
171
- "default": "N",
172
- "type": "checkbox",
173
- "link_info": "",
174
- "link_blog": "",
175
- "name": "Aggressive Scan",
176
- "summary": "Aggressively Block Data",
177
  "description": "Employs a set of aggressive rules to detect and block malicious data submitted to your site. Warning - May cause an increase in false-positive firewall blocks."
178
  },
179
  {
180
- "key": "block_response",
181
- "section": "section_choose_firewall_block_response",
182
- "default": "redirect_die_message",
183
- "type": "select",
184
  "value_options": [
185
  {
186
  "value_key": "redirect_die_message",
187
- "text": "Die With Message"
188
  },
189
  {
190
  "value_key": "redirect_die",
191
- "text": "Die"
192
  },
193
  {
194
  "value_key": "redirect_home",
195
- "text": "Redirect To Home Page"
196
  },
197
  {
198
  "value_key": "redirect_404",
199
- "text": "Return 404"
200
  }
201
  ],
202
- "link_info": "",
203
- "link_blog": "",
204
- "name": "Block Response",
205
- "summary": "How the firewall responds when it blocks a request",
206
- "description": "We recommend dying with a message so you know what might have occurred when the firewall blocks you."
207
  },
208
  {
209
- "key": "block_send_email",
210
- "section": "section_choose_firewall_block_response",
211
- "default": "N",
212
- "type": "checkbox",
213
- "link_info": "",
214
- "link_blog": "",
215
- "name": "Send Email Report",
216
- "summary": "When a visitor is blocked the firewall will send an email to the configured email address",
217
  "description": "Use with caution - if you get hit by automated bots you may send out too many emails and you could get blocked by your host."
218
  },
219
  {
220
- "key": "page_params_whitelist",
221
- "section": "section_whitelist",
222
- "default": "",
223
- "type": "comma_separated_lists",
224
- "link_info": "https://icwp.io/2a",
225
- "link_blog": "",
226
- "name": "Whitelist Parameters",
227
- "summary": "Detail pages and parameters that are whitelisted (ignored by the firewall)",
228
  "description": "This should be used with caution and you should only provide parameter names that you must have excluded"
229
  },
230
  {
231
- "key": "whitelist_admins",
232
- "section": "section_whitelist",
233
- "default": "N",
234
- "type": "checkbox",
235
- "link_info": "",
236
- "link_blog": "",
237
- "name": "Ignore Administrators",
238
- "summary": "Ignore Administrators",
239
  "description": "Authenticated administrator users will not be processed by the firewall rules."
240
  },
241
  {
242
- "key": "ignore_search_engines",
243
- "section": "section_whitelist",
244
- "default": "N",
245
- "type": "checkbox",
246
- "link_info": "",
247
- "link_blog": "",
248
- "name": "Ignore Search Engines",
249
- "summary": "Ignore Search Engine Bot Traffic",
250
  "description": "The firewall will try to recognise search engine spiders/bots and not apply firewall rules to them."
251
  },
252
  {
253
- "key": "text_firewalldie",
254
- "section": "section_user_messages",
255
- "premium": true,
256
- "default": "default",
257
- "type": "text",
258
- "link_info": "",
259
- "link_blog": "",
260
- "name": "Firewall Block Message",
261
- "summary": "Message Displayed To Visitor When A Firewall Block Is Triggered",
262
- "description": "When you select the option to display a message to the visitor, this is the message that is displayed."
263
- },
264
  {
265
  "key": "insights_last_firewall_block_at",
266
  "transferable": false,
@@ -268,10 +269,47 @@
268
  "default": 0
269
  }
270
  ],
271
-
272
  "definitions": {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  "firewall_patterns": {
274
- "dirtraversal": {
275
  "simple": [
276
  "etc/passwd",
277
  "proc/self/environ",
@@ -283,12 +321,12 @@
283
  "loopback"
284
  ]
285
  },
286
- "wpterms": {
287
  "simple": [
288
  "/**/",
289
  "wp-config.php"
290
  ],
291
- "regex": [
292
  "^wp_",
293
  "^user_login",
294
  "^user_pass",
@@ -301,33 +339,33 @@
301
  "\\x00"
302
  ]
303
  },
304
- "sqlqueries": {
305
  "regex": [
306
  "concat\\s*\\(",
307
  "group_concat",
308
  "union.*select"
309
  ]
310
  },
311
- "exefile": {
312
  "regex": [
313
  "\\.(dll|rb|py|exe|php[3-6]?|pl|perl|ph[34]|phl|phtml|phtm|sql|ini|jsp|asp|git|svn|tar)$"
314
  ]
315
  },
316
- "schema": {
317
  "simple": [
318
  ".shtml"
319
  ],
320
- "regex": [
321
  "^(http|https|ftp|file):"
322
  ]
323
  },
324
- "phpcode": {
325
  "simple": null,
326
- "regex": [
327
  "(include|include_once|require|require_once)\\s*\\(.*\\)"
328
  ]
329
  },
330
- "aggressive": {
331
  "simple": [
332
  "eval(",
333
  "(null)",
@@ -341,7 +379,7 @@
341
  "/tmp/",
342
  "boot.ini"
343
  ],
344
- "regex": [
345
  "GLOBALS(=|\\[|%%)",
346
  "REQUEST(=|\\[|%%)",
347
  "(`|\\<|\\>|\\[|\\]|\\{|\\}|\\?)",
1
  {
2
+ "slug": "firewall",
3
+ "properties": {
4
+ "slug": "firewall",
5
+ "name": "Firewall",
6
  "show_module_menu_item": true,
7
+ "storage_key": "firewall",
8
+ "tagline": "Automatically block malicious URLs and data sent to your site",
9
+ "show_central": true,
10
+ "access_restricted": true,
11
+ "premium": false,
12
+ "run_if_whitelisted": false,
13
+ "run_if_verified_bot": false,
14
+ "order": 30
15
  },
16
+ "sections": [
17
  {
18
+ "slug": "section_firewall_blocking_options",
19
+ "primary": true,
20
+ "title": "Firewall Blocking Options",
21
  "title_short": "Firewall Blocking",
22
+ "summary": [
23
  "Here you choose what kind of malicious data to scan for.",
24
  "Recommendation - Turn on as many options here as you can. If you find an incompatibility or something stops working, un-check 1 option at a time until you find the problem or review the Audit Trail."
25
  ]
26
  },
27
  {
28
+ "slug": "section_choose_firewall_block_response",
29
+ "title": "Choose Firewall Block Response",
30
  "title_short": "Firewall Response",
31
+ "summary": [
32
  "Here you choose how the plugin will respond when it detects malicious data.",
33
  "Recommendation - Choose the option 'Die With Message'."
34
  ]
35
  },
36
  {
37
+ "slug": "section_whitelist",
38
+ "title": "Whitelists - IPs, Pages, Parameters, and Users that by-pass the Firewall",
39
  "title_short": "Whitelist",
40
+ "summary": [
41
  "In principle you should not need to whitelist anything or anyone unless you have discovered a collision with another plugin.",
42
  "Recommendation - Do not whitelist anything unless you are confident in what you are doing."
43
  ]
44
  },
45
  {
46
+ "slug": "section_user_messages",
47
+ "title": "Customize Messages Shown To User",
48
  "title_short": "Visitor Messages",
49
+ "summary": [
 
50
  "Purpose - Customize the messages shown to visitors.",
51
  "Recommendation - Be sure to change the messages to suit your audience.",
52
  "Hint - To reset any message to its default, enter the text exactly: default"
53
  ]
54
  },
55
  {
56
+ "slug": "section_enable_plugin_feature_wordpress_firewall",
57
+ "title": "Enable Module: Firewall",
58
  "title_short": "Disable Module",
59
+ "summary": [
60
+ "Purpose - The Firewall is designed to analyse data sent to your website and block any requests that appear to be malicious.",
61
+ "Recommendation - Keep the Firewall feature turned on."
62
+ ]
63
  },
64
  {
65
+ "slug": "section_non_ui",
66
  "hidden": true
67
  }
68
  ],
69
+ "options": [
70
  {
71
+ "key": "enable_firewall",
72
+ "section": "section_enable_plugin_feature_wordpress_firewall",
73
+ "default": "Y",
74
+ "type": "checkbox",
75
+ "link_info": "https://icwp.io/43",
76
+ "link_blog": "https://icwp.io/wpsf01",
77
+ "name": "Enable Firewall",
78
+ "summary": "Enable (or Disable) The Firewall module",
79
  "description": "Un-Checking this option will completely disable the Firewall module"
80
  },
81
  {
82
+ "key": "include_cookie_checks",
83
+ "section": "section_firewall_blocking_options",
84
+ "default": "N",
85
+ "type": "checkbox",
86
+ "link_info": "",
87
+ "link_blog": "",
88
+ "name": "Include Cookies",
89
+ "summary": "Also Test Cookie Values In Firewall Tests",
90
  "description": "The firewall tests GET and POST, but with this option checked it will also check COOKIE values."
91
  },
92
  {
93
+ "key": "block_dir_traversal",
94
+ "section": "section_firewall_blocking_options",
95
+ "default": "Y",
96
+ "type": "checkbox",
97
+ "link_info": "",
98
+ "link_blog": "",
99
+ "name": "Directory Traversals",
100
+ "summary": "Block Directory Traversals",
101
  "description": "This will block directory traversal paths in in application parameters."
102
  },
103
  {
104
+ "key": "block_sql_queries",
105
+ "section": "section_firewall_blocking_options",
106
+ "default": "Y",
107
+ "type": "checkbox",
108
+ "link_info": "",
109
+ "link_blog": "",
110
+ "name": "SQL Queries",
111
+ "summary": "Block SQL Queries",
112
  "description": "This will block SQL in application parameters."
113
  },
114
  {
115
+ "key": "block_wordpress_terms",
116
+ "section": "section_firewall_blocking_options",
117
+ "default": "N",
118
+ "type": "checkbox",
119
+ "link_info": "",
120
+ "link_blog": "",
121
+ "name": "WordPress Terms",
122
+ "summary": "Block WordPress Specific Terms",
123
  "description": "This will block WordPress specific terms in application parameters (wp_, user_login, etc.)."
124
  },
125
  {
126
+ "key": "block_field_truncation",
127
+ "section": "section_firewall_blocking_options",
128
+ "default": "Y",
129
+ "type": "checkbox",
130
+ "link_info": "",
131
+ "link_blog": "",
132
+ "name": "Field Truncation",
133
+ "summary": "Block Field Truncation Attacks",
134
  "description": "This will block field truncation attacks in application parameters"
135
  },
136
  {
137
+ "key": "block_php_code",
138
+ "section": "section_firewall_blocking_options",
139
+ "default": "N",
140
+ "type": "checkbox",
141
+ "link_info": "",
142
+ "link_blog": "",
143
+ "name": "PHP Code",
144
+ "summary": "Block PHP Code Includes",
145
  "description": "This will block any data that appears to try and include PHP files. Will probably block saving within the Plugin/Theme file editors."
146
  },
147
  {
148
+ "key": "block_exe_file_uploads",
149
+ "section": "section_firewall_blocking_options",
150
+ "default": "N",
151
+ "type": "checkbox",
152
+ "link_info": "",
153
+ "link_blog": "",
154
+ "name": "Exe File Uploads",
155
+ "summary": "Block Executable File Uploads",
156
  "description": "This will block executable file uploads (.php, .exe, etc.)."
157
  },
158
  {
159
+ "key": "block_leading_schema",
160
+ "section": "section_firewall_blocking_options",
161
+ "default": "N",
162
+ "type": "checkbox",
163
+ "link_info": "",
164
+ "link_blog": "",
165
+ "name": "Leading Schemas",
166
+ "summary": "Block Leading Schemas (HTTPS / HTTP)",
167
  "description": "This will block leading schemas http:// and https:// in application parameters (off by default; may cause problems with other plugins)."
168
  },
169
  {
170
+ "key": "block_aggressive",
171
+ "section": "section_firewall_blocking_options",
172
+ "default": "N",
173
+ "type": "checkbox",
174
+ "link_info": "",
175
+ "link_blog": "",
176
+ "name": "Aggressive Scan",
177
+ "summary": "Aggressively Block Data",
178
  "description": "Employs a set of aggressive rules to detect and block malicious data submitted to your site. Warning - May cause an increase in false-positive firewall blocks."
179
  },
180
  {
181
+ "key": "block_response",
182
+ "section": "section_choose_firewall_block_response",
183
+ "default": "redirect_die_message",
184
+ "type": "select",
185
  "value_options": [
186
  {
187
  "value_key": "redirect_die_message",
188
+ "text": "Die With Message"
189
  },
190
  {
191
  "value_key": "redirect_die",
192
+ "text": "Die"
193
  },
194
  {
195
  "value_key": "redirect_home",
196
+ "text": "Redirect To Home Page"
197
  },
198
  {
199
  "value_key": "redirect_404",
200
+ "text": "Return 404"
201
  }
202
  ],
203
+ "link_info": "",
204
+ "link_blog": "",
205
+ "name": "Block Response",
206
+ "summary": "How the firewall responds when it blocks a request",
207
+ "description": "We recommend dying with a message so you know what might have occurred when the firewall blocks you."
208
  },
209
  {
210
+ "key": "block_send_email",
211
+ "section": "section_choose_firewall_block_response",
212
+ "default": "N",
213
+ "type": "checkbox",
214
+ "link_info": "",
215
+ "link_blog": "",
216
+ "name": "Send Email Report",
217
+ "summary": "When a visitor is blocked the firewall will send an email to the configured email address",
218
  "description": "Use with caution - if you get hit by automated bots you may send out too many emails and you could get blocked by your host."
219
  },
220
  {
221
+ "key": "page_params_whitelist",
222
+ "section": "section_whitelist",
223
+ "default": "",
224
+ "type": "comma_separated_lists",
225
+ "link_info": "https://icwp.io/2a",
226
+ "link_blog": "",
227
+ "name": "Whitelist Parameters",
228
+ "summary": "Detail pages and parameters that are whitelisted (ignored by the firewall)",
229
  "description": "This should be used with caution and you should only provide parameter names that you must have excluded"
230
  },
231
  {
232
+ "key": "whitelist_admins",
233
+ "section": "section_whitelist",
234
+ "default": "N",
235
+ "type": "checkbox",
236
+ "link_info": "",
237
+ "link_blog": "",
238
+ "name": "Ignore Administrators",
239
+ "summary": "Ignore Administrators",
240
  "description": "Authenticated administrator users will not be processed by the firewall rules."
241
  },
242
  {
243
+ "key": "ignore_search_engines",
244
+ "section": "section_whitelist",
245
+ "default": "N",
246
+ "type": "checkbox",
247
+ "link_info": "",
248
+ "link_blog": "",
249
+ "name": "Ignore Search Engines",
250
+ "summary": "Ignore Search Engine Bot Traffic",
251
  "description": "The firewall will try to recognise search engine spiders/bots and not apply firewall rules to them."
252
  },
253
  {
254
+ "key": "text_firewalldie",
255
+ "section": "section_user_messages",
256
+ "premium": true,
257
+ "default": "default",
258
+ "type": "text",
259
+ "link_info": "",
260
+ "link_blog": "",
261
+ "name": "Firewall Block Message",
262
+ "summary": "Message Displayed To Visitor When A Firewall Block Is Triggered",
263
+ "description": "When you select the option to display a message to the visitor, this is the message that is displayed."
264
+ },
265
  {
266
  "key": "insights_last_firewall_block_at",
267
  "transferable": false,
269
  "default": 0
270
  }
271
  ],
 
272
  "definitions": {
273
+ "default_whitelist": {
274
+ "/wp-admin/options-general.php": [],
275
+ "/wp-admin/options.php": [
276
+ "home",
277
+ "siteurl"
278
+ ],
279
+ "/wp-admin/post-new.php": [],
280
+ "/wp-admin/page-new.php": [],
281
+ "/wp-admin/link-add.php": [],
282
+ "/wp-admin/media-upload.php": [],
283
+ "/wp-admin/post.php": [
284
+ "content"
285
+ ],
286
+ "/wp-admin/plugin-editor.php": [
287
+ "newcontent"
288
+ ],
289
+ "/wp-admin/page.php": [],
290
+ "/wp-admin/admin-ajax.php": [],
291
+ "/wp-comments-post.php": [
292
+ "url",
293
+ "comment"
294
+ ],
295
+ "*": [
296
+ "g-recaptcha-response",
297
+ "verify_sign",
298
+ "txn_id",
299
+ "wp_http_referer",
300
+ "_wp_http_referer",
301
+ "_wp_original_http_referer",
302
+ "pwd",
303
+ "url",
304
+ "referredby",
305
+ "redirect_to",
306
+ "jetpack_sso_original_request",
307
+ "jetpack_sso_redirect_to",
308
+ "/^wordpress_logged_in_[0-9a-f]+$/"
309
+ ]
310
+ },
311
  "firewall_patterns": {
312
+ "dirtraversal": {
313
  "simple": [
314
  "etc/passwd",
315
  "proc/self/environ",
321
  "loopback"
322
  ]
323
  },
324
+ "wpterms": {
325
  "simple": [
326
  "/**/",
327
  "wp-config.php"
328
  ],
329
+ "regex": [
330
  "^wp_",
331
  "^user_login",
332
  "^user_pass",
339
  "\\x00"
340
  ]
341
  },
342
+ "sqlqueries": {
343
  "regex": [
344
  "concat\\s*\\(",
345
  "group_concat",
346
  "union.*select"
347
  ]
348
  },
349
+ "exefile": {
350
  "regex": [
351
  "\\.(dll|rb|py|exe|php[3-6]?|pl|perl|ph[34]|phl|phtml|phtm|sql|ini|jsp|asp|git|svn|tar)$"
352
  ]
353
  },
354
+ "schema": {
355
  "simple": [
356
  ".shtml"
357
  ],
358
+ "regex": [
359
  "^(http|https|ftp|file):"
360
  ]
361
  },
362
+ "phpcode": {
363
  "simple": null,
364
+ "regex": [
365
  "(include|include_once|require|require_once)\\s*\\(.*\\)"
366
  ]
367
  },
368
+ "aggressive": {
369
  "simple": [
370
  "eval(",
371
  "(null)",
379
  "/tmp/",
380
  "boot.ini"
381
  ],
382
+ "regex": [
383
  "GLOBALS(=|\\[|%%)",
384
  "REQUEST(=|\\[|%%)",
385
  "(`|\\<|\\>|\\[|\\]|\\{|\\}|\\?)",
src/config/feature-hack_protect.php CHANGED
@@ -10,7 +10,8 @@
10
  "access_restricted": true,
11
  "premium": false,
12
  "order": 70,
13
- "whitelist_exempt": true
 
14
  },
15
  "sections": [
16
  {
10
  "access_restricted": true,
11
  "premium": false,
12
  "order": 70,
13
+ "run_if_whitelisted": true,
14
+ "run_if_verified_bot": true
15
  },
16
  "sections": [
17
  {
src/config/feature-headers.php CHANGED
@@ -1,241 +1,243 @@
1
  {
2
- "slug": "headers",
3
  "properties": {
4
- "slug": "headers",
5
- "name": "HTTP Headers",
6
  "show_module_menu_item": true,
7
- "storage_key": "headers",
8
- "tagline": "Control HTTP Security Headers",
9
- "show_central": true,
10
- "access_restricted": true,
11
- "premium": false,
12
- "order": 80
 
 
13
  },
14
- "sections": [
15
  {
16
- "slug": "section_security_headers",
17
- "primary": true,
18
- "title": "Advanced Security Headers",
19
  "title_short": "Security Headers",
20
- "summary": [
21
  "Purpose - Protect visitors to your site by implementing increased security response headers.",
22
  "Recommendation - Enabling these features are advised, but you must test them on your site thoroughly."
23
  ]
24
  },
25
  {
26
- "slug": "section_content_security_policy",
27
- "title": "Content Security Policy",
28
  "title_short": "Content Security Policy",
29
- "summary": [
30
  "Purpose - Restrict the sources and types of content that may be loaded and processed by visitor browsers.",
31
  "Recommendation - Enabling these features are advised, but you must test them on your site thoroughly."
32
  ]
33
  },
34
  {
35
- "slug": "section_enable_plugin_feature_headers",
36
- "title": "Enable Module: HTTP Headers",
37
  "title_short": "Disable Module",
38
- "summary": [
39
  "Purpose - Protect visitors to your site by implementing increased security response headers.",
40
  "Recommendation - Enabling these features are advised, but you must test them on your site thoroughly."
41
  ]
42
  },
43
  {
44
- "slug": "section_non_ui",
45
  "hidden": true
46
  }
47
  ],
48
- "options": [
49
- {
50
- "key": "enable_headers",
51
- "section": "section_enable_plugin_feature_headers",
52
- "default": "Y",
53
- "type": "checkbox",
54
- "link_info": "https://icwp.io/7c",
55
- "link_blog": "https://icwp.io/7c",
56
- "name": "Enable HTTP Headers",
57
- "summary": "Enable (or Disable) The HTTP Headers module",
58
  "description": "Un-Checking this option will completely disable the HTTP Headers module"
59
  },
60
  {
61
- "key": "x_frame",
62
- "section": "section_security_headers",
63
- "default": "on_sameorigin",
64
- "type": "select",
65
  "value_options": [
66
  {
67
  "value_key": "off",
68
- "text": "Off: iFrames Not Blocked"
69
  },
70
  {
71
  "value_key": "on_sameorigin",
72
- "text": "On: Allow iFrames On The Same Domain"
73
  },
74
  {
75
  "value_key": "on_deny",
76
- "text": "On: Block All iFrames"
77
  }
78
  ],
79
- "link_info": "https://icwp.io/78",
80
- "link_blog": "https://icwp.io/7c",
81
- "name": "Block iFrames",
82
- "summary": "Block Remote iFrames Of This Site",
83
- "description": "The setting prevents any external website from embedding your site in an iFrame. This is useful for preventing so-called ClickJack attacks."
84
  },
85
  {
86
- "key": "x_xss_protect",
87
- "section": "section_security_headers",
88
- "default": "Y",
89
- "type": "checkbox",
90
- "link_info": "https://icwp.io/79",
91
- "link_blog": "https://icwp.io/7c",
92
- "name": "XSS Protection",
93
- "summary": "Employ Built-In Browser XSS Protection",
94
  "description": "Directs compatible browsers to block what they detect as Reflective XSS attacks."
95
  },
96
  {
97
- "key": "x_content_type",
98
- "section": "section_security_headers",
99
- "default": "Y",
100
- "type": "checkbox",
101
- "link_info": "https://icwp.io/7a",
102
- "link_blog": "https://icwp.io/7c",
103
- "name": "Prevent Mime-Sniff",
104
- "summary": "Turn-Off Browser Mime-Sniff",
105
  "description": "Reduces visitor exposure to malicious user-uploaded content."
106
  },
107
  {
108
- "key": "x_referrer_policy",
109
- "section": "section_security_headers",
110
- "sensitive": false,
111
- "type": "select",
112
- "default": "unsafe-url",
113
  "value_options": [
114
  {
115
  "value_key": "unsafe-url",
116
- "text": "Default: Full Referrer URL (AKA 'Unsafe URL')"
117
  },
118
  {
119
  "value_key": "no-referrer",
120
- "text": "No Referrer"
121
  },
122
  {
123
  "value_key": "no-referrer-when-downgrade",
124
- "text": "No Referrer When Downgrade"
125
  },
126
  {
127
  "value_key": "same-origin",
128
- "text": "Same Origin"
129
  },
130
  {
131
  "value_key": "origin",
132
- "text": "Origin"
133
  },
134
  {
135
  "value_key": "strict-origin",
136
- "text": "Strict Origin"
137
  },
138
  {
139
  "value_key": "origin-when-cross-origin",
140
- "text": "Origin When Cross-Origin"
141
  },
142
  {
143
  "value_key": "strict-origin-when-cross-origin",
144
- "text": "Strict Origin When Cross-Origin"
145
  },
146
  {
147
  "value_key": "empty",
148
- "text": "Empty Header"
149
  },
150
  {
151
  "value_key": "disabled",
152
- "text": "Don't Send This Header"
153
  }
154
  ],
155
- "link_info": "https://icwp.io/a5",
156
- "link_blog": "",
157
- "name": "Referrer Policy",
158
- "summary": "Referrer Policy Header",
159
- "description": "The Referrer Policy Header allows you to control when and what referral information a browser may pass along with links clicked on your site."
160
  },
161
  {
162
- "key": "enable_x_content_security_policy",
163
- "section": "section_content_security_policy",
164
- "default": "N",
165
- "type": "checkbox",
166
- "link_info": "https://icwp.io/7d",
167
- "link_blog": "https://icwp.io/7c",
168
- "name": "Enable Content Security Policy",
169
- "summary": "Enable (or Disable) The Content Security Policy module",
170
  "description": "Allows for permission and restriction of all resources loaded on your site."
171
  },
172
  {
173
- "key": "xcsp_self",
174
- "section": "section_content_security_policy",
175
- "default": "Y",
176
- "type": "checkbox",
177
- "link_info": "",
178
- "link_blog": "",
179
- "name": "Self",
180
- "summary": "Allow 'self' Directive",
181
  "description": "Using 'self' is generally recommended. It essentially means that resources from your own host:protocol are permitted."
182
  },
183
  {
184
- "key": "xcsp_inline",
185
- "section": "section_content_security_policy",
186
- "default": "Y",
187
- "type": "checkbox",
188
- "link_info": "",
189
- "link_blog": "",
190
- "name": "Inline Entities",
191
- "summary": "Allow Inline Scripts and CSS",
192
  "description": "Allows parsing of Javascript and CSS declared in-line in your html document."
193
  },
194
  {
195
- "key": "xcsp_data",
196
- "section": "section_content_security_policy",
197
- "default": "Y",
198
- "type": "checkbox",
199
- "link_info": "",
200
- "link_blog": "",
201
- "name": "Embedded Data",
202
- "summary": "Allow 'data:' Directives",
203
  "description": "Allows use of embedded data directives, most commonly used for images and fonts."
204
  },
205
  {
206
- "key": "xcsp_eval",
207
- "section": "section_content_security_policy",
208
- "default": "Y",
209
- "type": "checkbox",
210
- "link_info": "",
211
- "link_blog": "",
212
- "name": "Allow eval()",
213
- "summary": "Allow Javascript eval()",
214
  "description": "Permits the use of Javascript the eval() function."
215
  },
216
  {
217
- "key": "xcsp_https",
218
- "section": "section_content_security_policy",
219
- "default": "N",
220
- "type": "checkbox",
221
- "link_info": "",
222
- "link_blog": "",
223
- "name": "HTTPS",
224
- "summary": "HTTPS Resource Loading",
225
  "description": "Allows loading of any content provided over HTTPS."
226
  },
227
  {
228
- "key": "xcsp_hosts",
229
- "section": "section_content_security_policy",
230
- "sensitive": true,
231
- "default": [
232
  "*"
233
  ],
234
- "type": "array",
235
- "link_info": "",
236
- "link_blog": "",
237
- "name": "Permitted Hosts",
238
- "summary": "Permitted Hosts and Domains",
239
  "description": "You can explicitly state which hosts/domain from which content may be loaded. Take great care and test your site as you may block legitimate resources. If in-doubt, leave blank or use '*' only. Note: You can force only HTTPS for a given domain by prefixing it with 'https://'."
240
  }
241
  ]
1
  {
2
+ "slug": "headers",
3
  "properties": {
4
+ "slug": "headers",
5
+ "name": "HTTP Headers",
6
  "show_module_menu_item": true,
7
+ "storage_key": "headers",
8
+ "tagline": "Control HTTP Security Headers",
9
+ "show_central": true,
10
+ "access_restricted": true,
11
+ "premium": false,
12
+ "run_if_whitelisted": false,
13
+ "run_if_verified_bot": true,
14
+ "order": 80
15
  },
16
+ "sections": [
17
  {
18
+ "slug": "section_security_headers",
19
+ "primary": true,
20
+ "title": "Advanced Security Headers",
21
  "title_short": "Security Headers",
22
+ "summary": [
23
  "Purpose - Protect visitors to your site by implementing increased security response headers.",
24
  "Recommendation - Enabling these features are advised, but you must test them on your site thoroughly."
25
  ]
26
  },
27
  {
28
+ "slug": "section_content_security_policy",
29
+ "title": "Content Security Policy",
30
  "title_short": "Content Security Policy",
31
+ "summary": [
32
  "Purpose - Restrict the sources and types of content that may be loaded and processed by visitor browsers.",
33
  "Recommendation - Enabling these features are advised, but you must test them on your site thoroughly."
34
  ]
35
  },
36
  {
37
+ "slug": "section_enable_plugin_feature_headers",
38
+ "title": "Enable Module: HTTP Headers",
39
  "title_short": "Disable Module",
40
+ "summary": [
41
  "Purpose - Protect visitors to your site by implementing increased security response headers.",
42
  "Recommendation - Enabling these features are advised, but you must test them on your site thoroughly."
43
  ]
44
  },
45
  {
46
+ "slug": "section_non_ui",
47
  "hidden": true
48
  }
49
  ],
50
+ "options": [
51
+ {
52
+ "key": "enable_headers",
53
+ "section": "section_enable_plugin_feature_headers",
54
+ "default": "Y",
55
+ "type": "checkbox",
56
+ "link_info": "https://icwp.io/7c",
57
+ "link_blog": "https://icwp.io/7c",
58
+ "name": "Enable HTTP Headers",
59
+ "summary": "Enable (or Disable) The HTTP Headers module",
60
  "description": "Un-Checking this option will completely disable the HTTP Headers module"
61
  },
62
  {
63
+ "key": "x_frame",
64
+ "section": "section_security_headers",
65
+ "default": "on_sameorigin",
66
+ "type": "select",
67
  "value_options": [
68
  {
69
  "value_key": "off",
70
+ "text": "Off: iFrames Not Blocked"
71
  },
72
  {
73
  "value_key": "on_sameorigin",
74
+ "text": "On: Allow iFrames On The Same Domain"
75
  },
76
  {
77
  "value_key": "on_deny",
78
+ "text": "On: Block All iFrames"
79
  }
80
  ],
81
+ "link_info": "https://icwp.io/78",
82
+ "link_blog": "https://icwp.io/7c",
83
+ "name": "Block iFrames",
84
+ "summary": "Block Remote iFrames Of This Site",
85
+ "description": "The setting prevents any external website from embedding your site in an iFrame. This is useful for preventing so-called ClickJack attacks."
86
  },
87
  {
88
+ "key": "x_xss_protect",
89
+ "section": "section_security_headers",
90
+ "default": "Y",
91
+ "type": "checkbox",
92
+ "link_info": "https://icwp.io/79",
93
+ "link_blog": "https://icwp.io/7c",
94
+ "name": "XSS Protection",
95
+ "summary": "Employ Built-In Browser XSS Protection",
96
  "description": "Directs compatible browsers to block what they detect as Reflective XSS attacks."
97
  },
98
  {
99
+ "key": "x_content_type",
100
+ "section": "section_security_headers",
101
+ "default": "Y",
102
+ "type": "checkbox",
103
+ "link_info": "https://icwp.io/7a",
104
+ "link_blog": "https://icwp.io/7c",
105
+ "name": "Prevent Mime-Sniff",
106
+ "summary": "Turn-Off Browser Mime-Sniff",
107
  "description": "Reduces visitor exposure to malicious user-uploaded content."
108
  },
109
  {
110
+ "key": "x_referrer_policy",
111
+ "section": "section_security_headers",
112
+ "sensitive": false,
113
+ "type": "select",
114
+ "default": "unsafe-url",
115
  "value_options": [
116
  {
117
  "value_key": "unsafe-url",
118
+ "text": "Default: Full Referrer URL (AKA 'Unsafe URL')"
119
  },
120
  {
121
  "value_key": "no-referrer",
122
+ "text": "No Referrer"
123
  },
124
  {
125
  "value_key": "no-referrer-when-downgrade",
126
+ "text": "No Referrer When Downgrade"
127
  },
128
  {
129
  "value_key": "same-origin",
130
+ "text": "Same Origin"
131
  },
132
  {
133
  "value_key": "origin",
134
+ "text": "Origin"
135
  },
136
  {
137
  "value_key": "strict-origin",
138
+ "text": "Strict Origin"
139
  },
140
  {
141
  "value_key": "origin-when-cross-origin",
142
+ "text": "Origin When Cross-Origin"
143
  },
144
  {
145
  "value_key": "strict-origin-when-cross-origin",
146
+ "text": "Strict Origin When Cross-Origin"
147
  },
148
  {
149
  "value_key": "empty",
150
+ "text": "Empty Header"
151
  },
152
  {
153
  "value_key": "disabled",
154
+ "text": "Don't Send This Header"
155
  }
156
  ],
157
+ "link_info": "https://icwp.io/a5",
158
+ "link_blog": "",
159
+ "name": "Referrer Policy",
160
+ "summary": "Referrer Policy Header",
161
+ "description": "The Referrer Policy Header allows you to control when and what referral information a browser may pass along with links clicked on your site."
162
  },
163
  {
164
+ "key": "enable_x_content_security_policy",
165
+ "section": "section_content_security_policy",
166
+ "default": "N",
167
+ "type": "checkbox",
168
+ "link_info": "https://icwp.io/7d",
169
+ "link_blog": "https://icwp.io/7c",
170
+ "name": "Enable Content Security Policy",
171
+ "summary": "Enable (or Disable) The Content Security Policy module",
172
  "description": "Allows for permission and restriction of all resources loaded on your site."
173
  },
174
  {
175
+ "key": "xcsp_self",
176
+ "section": "section_content_security_policy",
177
+ "default": "Y",
178
+ "type": "checkbox",
179
+ "link_info": "",
180
+ "link_blog": "",
181
+ "name": "Self",
182
+ "summary": "Allow 'self' Directive",
183
  "description": "Using 'self' is generally recommended. It essentially means that resources from your own host:protocol are permitted."
184
  },
185
  {
186
+ "key": "xcsp_inline",
187
+ "section": "section_content_security_policy",
188
+ "default": "Y",
189
+ "type": "checkbox",
190
+ "link_info": "",
191
+ "link_blog": "",
192
+ "name": "Inline Entities",
193
+ "summary": "Allow Inline Scripts and CSS",
194
  "description": "Allows parsing of Javascript and CSS declared in-line in your html document."
195
  },
196
  {
197
+ "key": "xcsp_data",
198
+ "section": "section_content_security_policy",
199
+ "default": "Y",
200
+ "type": "checkbox",
201
+ "link_info": "",
202
+ "link_blog": "",
203
+ "name": "Embedded Data",
204
+ "summary": "Allow 'data:' Directives",
205
  "description": "Allows use of embedded data directives, most commonly used for images and fonts."
206
  },
207
  {
208
+ "key": "xcsp_eval",
209
+ "section": "section_content_security_policy",
210
+ "default": "Y",
211
+ "type": "checkbox",
212
+ "link_info": "",
213
+ "link_blog": "",
214
+ "name": "Allow eval()",
215
+ "summary": "Allow Javascript eval()",
216
  "description": "Permits the use of Javascript the eval() function."
217
  },
218
  {
219
+ "key": "xcsp_https",
220
+ "section": "section_content_security_policy",
221
+ "default": "N",
222
+ "type": "checkbox",
223
+ "link_info": "",
224
+ "link_blog": "",
225
+ "name": "HTTPS",
226
+ "summary": "HTTPS Resource Loading",
227
  "description": "Allows loading of any content provided over HTTPS."
228
  },
229
  {
230
+ "key": "xcsp_hosts",
231
+ "section": "section_content_security_policy",
232
+ "sensitive": true,
233
+ "default": [
234
  "*"
235
  ],
236
+ "type": "array",
237
+ "link_info": "",
238
+ "link_blog": "",
239
+ "name": "Permitted Hosts",
240
+ "summary": "Permitted Hosts and Domains",
241
  "description": "You can explicitly state which hosts/domain from which content may be loaded. Take great care and test your site as you may block legitimate resources. If in-doubt, leave blank or use '*' only. Note: You can force only HTTPS for a given domain by prefixing it with 'https://'."
242
  }
243
  ]
src/config/feature-insights.php CHANGED
@@ -10,7 +10,8 @@
10
  "show_central": false,
11
  "premium": false,
12
  "access_restricted": true,
13
- "whitelist_exempt": true
 
14
  },
15
  "requirements": {
16
  "php": {
10
  "show_central": false,
11
  "premium": false,
12
  "access_restricted": true,
13
+ "run_if_whitelisted": true,
14
+ "run_if_verified_bot": false
15
  },
16
  "requirements": {
17
  "php": {
src/config/feature-ips.php CHANGED
@@ -10,7 +10,8 @@
10
  "access_restricted": true,
11
  "premium": false,
12
  "has_custom_actions": true,
13
- "whitelist_exempt": true,
 
14
  "order": 100
15
  },
16
  "admin_notices": {
@@ -134,6 +135,7 @@
134
  {
135
  "key": "text_loginfailed",
136
  "section": "section_user_messages",
 
137
  "premium": true,
138
  "default": "default",
139
  "type": "text",
@@ -173,6 +175,7 @@
173
  {
174
  "key": "text_remainingtrans",
175
  "section": "section_user_messages",
 
176
  "premium": true,
177
  "default": "default",
178
  "type": "text",
10
  "access_restricted": true,
11
  "premium": false,
12
  "has_custom_actions": true,
13
+ "run_if_whitelisted": true,
14
+ "run_if_verified_bot": true,
15
  "order": 100
16
  },
17
  "admin_notices": {
135
  {
136
  "key": "text_loginfailed",
137
  "section": "section_user_messages",
138
+ "sensitive": true,
139
  "premium": true,
140
  "default": "default",
141
  "type": "text",
175
  {
176
  "key": "text_remainingtrans",
177
  "section": "section_user_messages",
178
+ "sensitive": true,
179
  "premium": true,
180
  "default": "default",
181
  "type": "text",
src/config/feature-license.php CHANGED
@@ -11,7 +11,8 @@
11
  "show_central": false,
12
  "premium": false,
13
  "access_restricted": true,
14
- "whitelist_exempt": true
 
15
  },
16
  "sections": [
17
  {
11
  "show_central": false,
12
  "premium": false,
13
  "access_restricted": true,
14
+ "run_if_whitelisted": true,
15
+ "run_if_verified_bot": true
16
  },
17
  "sections": [
18
  {
src/config/feature-lockdown.php CHANGED
@@ -1,91 +1,93 @@
1
  {
2
- "slug": "lockdown",
3
  "properties": {
4
- "slug": "lockdown",
5
- "name": "Lockdown",
6
  "show_module_menu_item": true,
7
- "storage_key": "lockdown",
8
- "tagline": "Harden the more loosely controlled settings of your site",
9
- "show_central": true,
10
- "access_restricted": true,
11
- "premium": false,
12
- "order": 90
 
 
13
  },
14
- "sections": [
15
  {
16
- "slug": "section_apixml",
17
- "primary": true,
18
- "title": "WordPress System Lockdown",
19
  "title_short": "System",
20
- "summary": [
21
  "Purpose - Lockdown certain core WordPress system features.",
22
  "Recommendation - This depends on your usage and needs for certain WordPress functions and features."
23
  ]
24
  },
25
  {
26
- "slug": "section_permission_access_options",
27
- "title": "Permissions and Access Options",
28
  "title_short": "Permissions",
29
- "summary": [
30
  "Purpose - Provides finer control of certain WordPress permissions.",
31
  "Recommendation - Only enable SSL if you have a valid certificate installed."
32
  ]
33
  },
34
  {
35
- "slug": "section_wordpress_obscurity_options",
36
- "title": "WordPress Obscurity Options",
37
  "title_short": "Obscurity",
38
- "summary": [
39
  "Purpose - Obscures certain WordPress settings from public view.",
40
  "Recommendation - Obscurity is not true security and so these settings are down to your personal tastes."
41
  ]
42
  },
43
  {
44
- "slug": "section_enable_plugin_feature_wordpress_lockdown",
45
- "title": "Enable Module: Lockdown",
46
  "title_short": "Disable Module",
47
- "summary": [
48
  "Purpose - Lockdown helps secure-up certain loosely-controlled WordPress settings on your site.",
49
  "Recommendation - Keep the Lockdown feature turned on."
50
  ]
51
  },
52
  {
53
- "slug": "section_non_ui",
54
  "hidden": true
55
  }
56
  ],
57
- "options": [
58
- {
59
- "key": "enable_lockdown",
60
- "section": "section_enable_plugin_feature_wordpress_lockdown",
61
- "default": "Y",
62
- "type": "checkbox",
63
- "link_info": "https://icwp.io/4r",
64
- "link_blog": "",
65
- "name": "Enable Lockdown",
66
- "summary": "Enable (or Disable) The Lockdown module",
67
  "description": "Un-Checking this option will completely disable the Lockdown module"
68
  },
69
  {
70
- "key": "disable_xmlrpc",
71
- "section": "section_apixml",
72
- "default": "N",
73
- "type": "checkbox",
74
- "link_info": "",
75
- "link_blog": "",
76
- "name": "Disable XML-RPC",
77
- "summary": "Disable The XML-RPC System",
78
  "description": "Checking this option will completely turn off the whole XML-RPC system."
79
  },
80
  {
81
- "key": "disable_anonymous_restapi",
82
- "section": "section_apixml",
83
- "default": "N",
84
- "type": "checkbox",
85
- "link_info": "",
86
- "link_blog": "",
87
- "name": "Anonymous Rest API",
88
- "summary": "Disable The Anonymous Rest API",
89
  "description": "Checking this option will completely turn off the whole Anonymous Rest API system."
90
  },
91
  {
@@ -104,58 +106,58 @@
104
  "description": "Any namespaces provided here will be excluded from the Anonymous API restriction."
105
  },
106
  {
107
- "key": "disable_file_editing",
108
- "section": "section_permission_access_options",
109
- "default": "N",
110
- "type": "checkbox",
111
- "link_info": "https://icwp.io/4q",
112
- "link_blog": "",
113
- "name": "Disable File Editing",
114
- "summary": "Disable Ability To Edit Files From Within WordPress",
115
  "description": "Removes the option to directly edit any files from within the WordPress admin area. Equivalent to setting 'DISALLOW_FILE_EDIT' to TRUE."
116
  },
117
  {
118
- "key": "force_ssl_admin",
119
- "section": "section_permission_access_options",
120
- "default": "N",
121
- "type": "checkbox",
122
- "link_info": "https://icwp.io/4t",
123
- "link_blog": "",
124
- "name": "Force SSL Admin",
125
- "summary": "Forces WordPress Admin Dashboard To Be Delivered Over SSL",
126
  "description": "Please only enable this option if you have a valid SSL certificate installed. Equivalent to setting 'FORCE_SSL_ADMIN' to TRUE."
127
  },
128
  {
129
- "key": "mask_wordpress_version",
130
- "section": "section_wordpress_obscurity_options",
131
- "default": "",
132
- "type": "text",
133
- "link_info": "https://icwp.io/43",
134
- "link_blog": "",
135
- "name": "Mask WordPress Version",
136
- "summary": "Prevents Public Display Of Your WordPress Version",
137
  "description": "Enter how you would like your WordPress version displayed publicly. Leave blank to disable this feature. Warning: This may interfere with WordPress plugins that rely on the $wp_version variable."
138
  },
139
  {
140
- "key": "hide_wordpress_generator_tag",
141
- "section": "section_wordpress_obscurity_options",
142
- "default": "N",
143
- "type": "checkbox",
144
- "link_info": "",
145
- "link_blog": "",
146
- "name": "WP Generator Tag",
147
- "summary": "Remove WP Generator Meta Tag",
148
  "description": "Remove a meta tag from your WordPress pages that publicly displays that your site is WordPress and its current version."
149
  },
150
  {
151
- "key": "block_author_discovery",
152
- "section": "section_wordpress_obscurity_options",
153
- "default": "Y",
154
- "type": "checkbox",
155
- "link_info": "https://icwp.io/wpsf23",
156
- "link_blog": "",
157
- "name": "Block Username Fishing",
158
- "summary": "Block the ability to discover WordPress usernames based on author IDs",
159
  "description": "When enabled, any URL requests containing 'author=' will be killed. Warning: Enabling this option may interfere with expected operations of your site."
160
  },
161
  {
1
  {
2
+ "slug": "lockdown",
3
  "properties": {
4
+ "slug": "lockdown",
5
+ "name": "Lockdown",
6
  "show_module_menu_item": true,
7
+ "storage_key": "lockdown",
8
+ "tagline": "Harden the more loosely controlled settings of your site",
9
+ "show_central": true,
10
+ "access_restricted": true,
11
+ "premium": false,
12
+ "run_if_whitelisted": false,
13
+ "run_if_verified_bot": false,
14
+ "order": 90
15
  },
16
+ "sections": [
17
  {
18
+ "slug": "section_apixml",
19
+ "primary": true,
20
+ "title": "WordPress System Lockdown",
21
  "title_short": "System",
22
+ "summary": [
23
  "Purpose - Lockdown certain core WordPress system features.",
24
  "Recommendation - This depends on your usage and needs for certain WordPress functions and features."
25
  ]
26
  },
27
  {
28
+ "slug": "section_permission_access_options",
29
+ "title": "Permissions and Access Options",
30
  "title_short": "Permissions",
31
+ "summary": [
32
  "Purpose - Provides finer control of certain WordPress permissions.",
33
  "Recommendation - Only enable SSL if you have a valid certificate installed."
34
  ]
35
  },
36
  {
37
+ "slug": "section_wordpress_obscurity_options",
38
+ "title": "WordPress Obscurity Options",
39
  "title_short": "Obscurity",
40
+ "summary": [
41
  "Purpose - Obscures certain WordPress settings from public view.",
42
  "Recommendation - Obscurity is not true security and so these settings are down to your personal tastes."
43
  ]
44
  },
45
  {
46
+ "slug": "section_enable_plugin_feature_wordpress_lockdown",
47
+ "title": "Enable Module: Lockdown",
48
  "title_short": "Disable Module",
49
+ "summary": [
50
  "Purpose - Lockdown helps secure-up certain loosely-controlled WordPress settings on your site.",
51
  "Recommendation - Keep the Lockdown feature turned on."
52
  ]
53
  },
54
  {
55
+ "slug": "section_non_ui",
56
  "hidden": true
57
  }
58
  ],
59
+ "options": [
60
+ {
61
+ "key": "enable_lockdown",
62
+ "section": "section_enable_plugin_feature_wordpress_lockdown",
63
+ "default": "Y",
64
+ "type": "checkbox",
65
+ "link_info": "https://icwp.io/4r",
66
+ "link_blog": "",
67
+ "name": "Enable Lockdown",
68
+ "summary": "Enable (or Disable) The Lockdown module",
69
  "description": "Un-Checking this option will completely disable the Lockdown module"
70
  },
71
  {
72
+ "key": "disable_xmlrpc",
73
+ "section": "section_apixml",
74
+ "default": "N",
75
+ "type": "checkbox",
76
+ "link_info": "",
77
+ "link_blog": "",
78
+ "name": "Disable XML-RPC",
79
+ "summary": "Disable The XML-RPC System",
80
  "description": "Checking this option will completely turn off the whole XML-RPC system."
81
  },
82
  {
83
+ "key": "disable_anonymous_restapi",
84
+ "section": "section_apixml",
85
+ "default": "N",
86
+ "type": "checkbox",
87
+ "link_info": "",
88
+ "link_blog": "",
89
+ "name": "Anonymous Rest API",
90
+ "summary": "Disable The Anonymous Rest API",
91
  "description": "Checking this option will completely turn off the whole Anonymous Rest API system."
92
  },
93
  {
106
  "description": "Any namespaces provided here will be excluded from the Anonymous API restriction."
107
  },
108
  {
109
+ "key": "disable_file_editing",
110
+ "section": "section_permission_access_options",
111
+ "default": "N",
112
+ "type": "checkbox",
113
+ "link_info": "https://icwp.io/4q",
114
+ "link_blog": "",
115
+ "name": "Disable File Editing",
116
+ "summary": "Disable Ability To Edit Files From Within WordPress",
117
  "description": "Removes the option to directly edit any files from within the WordPress admin area. Equivalent to setting 'DISALLOW_FILE_EDIT' to TRUE."
118
  },
119
  {
120
+ "key": "force_ssl_admin",
121
+ "section": "section_permission_access_options",
122
+ "default": "N",
123
+ "type": "checkbox",
124
+ "link_info": "https://icwp.io/4t",
125
+ "link_blog": "",
126
+ "name": "Force SSL Admin",
127
+ "summary": "Forces WordPress Admin Dashboard To Be Delivered Over SSL",
128
  "description": "Please only enable this option if you have a valid SSL certificate installed. Equivalent to setting 'FORCE_SSL_ADMIN' to TRUE."
129
  },
130
  {
131
+ "key": "mask_wordpress_version",
132
+ "section": "section_wordpress_obscurity_options",
133
+ "default": "",
134
+ "type": "text",
135
+ "link_info": "https://icwp.io/43",
136
+ "link_blog": "",
137
+ "name": "Mask WordPress Version",
138
+ "summary": "Prevents Public Display Of Your WordPress Version",
139
  "description": "Enter how you would like your WordPress version displayed publicly. Leave blank to disable this feature. Warning: This may interfere with WordPress plugins that rely on the $wp_version variable."
140
  },
141
  {
142
+ "key": "hide_wordpress_generator_tag",
143
+ "section": "section_wordpress_obscurity_options",
144
+ "default": "N",
145
+ "type": "checkbox",
146
+ "link_info": "",
147
+ "link_blog": "",
148
+ "name": "WP Generator Tag",
149
+ "summary": "Remove WP Generator Meta Tag",
150
  "description": "Remove a meta tag from your WordPress pages that publicly displays that your site is WordPress and its current version."
151
  },
152
  {
153
+ "key": "block_author_discovery",
154
+ "section": "section_wordpress_obscurity_options",
155
+ "default": "Y",
156
+ "type": "checkbox",
157
+ "link_info": "https://icwp.io/wpsf23",
158
+ "link_blog": "",
159
+ "name": "Block Username Fishing",
160
+ "summary": "Block the ability to discover WordPress usernames based on author IDs",
161
  "description": "When enabled, any URL requests containing 'author=' will be killed. Warning: Enabling this option may interfere with expected operations of your site."
162
  },
163
  {
src/config/feature-login_protect.php CHANGED
@@ -9,6 +9,8 @@
9
  "show_central": true,
10
  "access_restricted": true,
11
  "premium": false,
 
 
12
  "order": 40
13
  },
14
  "admin_notices": {
@@ -159,6 +161,18 @@
159
  "summary": "A User Can By-Pass Multi-Factor Authentication (MFA) For The Set Number Of Days",
160
  "description": "Enter the number of days a user can by-pass future MFA after a successful MFA-login. 0 to disable."
161
  },
 
 
 
 
 
 
 
 
 
 
 
 
162
  {
163
  "key": "enable_google_authenticator",
164
  "section": "section_2fa_ga",
@@ -361,6 +375,7 @@
361
  {
362
  "key": "text_imahuman",
363
  "section": "section_user_messages",
 
364
  "premium": true,
365
  "default": "default",
366
  "type": "text",
@@ -373,6 +388,7 @@
373
  {
374
  "key": "text_pleasecheckbox",
375
  "section": "section_user_messages",
 
376
  "premium": true,
377
  "default": "default",
378
  "type": "text",
9
  "show_central": true,
10
  "access_restricted": true,
11
  "premium": false,
12
+ "run_if_whitelisted": false,
13
+ "run_if_verified_bot": false,
14
  "order": 40
15
  },
16
  "admin_notices": {
161
  "summary": "A User Can By-Pass Multi-Factor Authentication (MFA) For The Set Number Of Days",
162
  "description": "Enter the number of days a user can by-pass future MFA after a successful MFA-login. 0 to disable."
163
  },
164
+ {
165
+ "key": "allow_backupcodes",
166
+ "section": "section_multifactor_authentication",
167
+ "premium": true,
168
+ "default": "N",
169
+ "type": "checkbox",
170
+ "link_info": "",
171
+ "link_blog": "",
172
+ "name": "Allow Backup Codes",
173
+ "summary": "Allow Users To Generate A Backup Code",
174
+ "description": "Allow users to generate a backup code that can be used to login if MFA factors are unavailable."
175
+ },
176
  {
177
  "key": "enable_google_authenticator",
178
  "section": "section_2fa_ga",
375
  {
376
  "key": "text_imahuman",
377
  "section": "section_user_messages",
378
+ "sensitive": true,
379
  "premium": true,
380
  "default": "default",
381
  "type": "text",
388
  {
389
  "key": "text_pleasecheckbox",
390
  "section": "section_user_messages",
391
+ "sensitive": true,
392
  "premium": true,
393
  "default": "default",
394
  "type": "text",
src/config/feature-plugin.php CHANGED
@@ -10,7 +10,8 @@
10
  "access_restricted": true,
11
  "premium": false,
12
  "has_custom_actions": false,
13
- "whitelist_exempt": true,
 
14
  "order": 10
15
  },
16
  "admin_notices": {
@@ -54,13 +55,6 @@
54
  "valid_admin": true,
55
  "delay_days": 30,
56
  "type": "promo"
57
- },
58
- "translate-plugin": {
59
- "id": "translate-plugin",
60
- "schedule": "once",
61
- "valid_admin": true,
62
- "delay_days": 45,
63
- "type": "promo"
64
  }
65
  },
66
  "sections": [
@@ -395,6 +389,7 @@
395
  }
396
  ],
397
  "definitions": {
 
398
  "help_video_id": "",
399
  "tracking_cron_handle": "plugin_tracking_cron",
400
  "tracking_post_url": "https://tracking.icontrolwp.com/track/plugin/shield",
10
  "access_restricted": true,
11
  "premium": false,
12
  "has_custom_actions": false,
13
+ "run_if_whitelisted": true,
14
+ "run_if_verified_bot": true,
15
  "order": 10
16
  },
17
  "admin_notices": {
55
  "valid_admin": true,
56
  "delay_days": 30,
57
  "type": "promo"
 
 
 
 
 
 
 
58
  }
59
  },
60
  "sections": [
389
  }
390
  ],
391
  "definitions": {
392
+ "survey_email": "c3VwcG9ydEBvbmVkb2xsYXJwbHVnaW4uY29t",
393
  "help_video_id": "",
394
  "tracking_cron_handle": "plugin_tracking_cron",
395
  "tracking_post_url": "https://tracking.icontrolwp.com/track/plugin/shield",
src/config/feature-sessions.php CHANGED
@@ -10,7 +10,8 @@
10
  "premium": false,
11
  "access_restricted": true,
12
  "auto_load_processor": true,
13
- "whitelist_exempt": true
 
14
  },
15
  "sections": [
16
  {
@@ -57,6 +58,8 @@
57
  "logged_in_at",
58
  "last_activity_at",
59
  "last_activity_uri",
 
 
60
  "secadmin_at",
61
  "created_at",
62
  "deleted_at"
10
  "premium": false,
11
  "access_restricted": true,
12
  "auto_load_processor": true,
13
+ "run_if_whitelisted": true,
14
+ "run_if_verified_bot": true
15
  },
16
  "sections": [
17
  {
58
  "logged_in_at",
59
  "last_activity_at",
60
  "last_activity_uri",
61
+ "li_code_email",
62
+ "login_intent_expires_at",
63
  "secadmin_at",
64
  "created_at",
65
  "deleted_at"
src/config/feature-statistics.php CHANGED
@@ -8,7 +8,8 @@
8
  "show_central": false,
9
  "premium": false,
10
  "access_restricted": true,
11
- "whitelist_exempt": true
 
12
  },
13
  "sections": [
14
  {
8
  "show_central": false,
9
  "premium": false,
10
  "access_restricted": true,
11
+ "run_if_whitelisted": true,
12
+ "run_if_verified_bot": false
13
  },
14
  "sections": [
15
  {
src/config/feature-traffic.php CHANGED
@@ -10,7 +10,8 @@
10
  "access_restricted": true,
11
  "premium": true,
12
  "has_custom_actions": true,
13
- "whitelist_exempt": true,
 
14
  "order": 110
15
  },
16
  "requirements": {
@@ -88,7 +89,7 @@
88
  },
89
  {
90
  "value_key": "search",
91
- "text": "Search Bots (i.e. Google, Bing, DuckDuckGo)"
92
  },
93
  {
94
  "value_key": "uptime",
@@ -101,6 +102,17 @@
101
  "summary": "Select Which Types Of Requests To Exclude",
102
  "description": "Deselect any requests that you don't want to appear in the traffic viewer."
103
  },
 
 
 
 
 
 
 
 
 
 
 
104
  {
105
  "key": "auto_clean",
106
  "section": "section_traffic_options",
10
  "access_restricted": true,
11
  "premium": true,
12
  "has_custom_actions": true,
13
+ "run_if_whitelisted": false,
14
+ "run_if_verified_bot": true,
15
  "order": 110
16
  },
17
  "requirements": {
89
  },
90
  {
91
  "value_key": "search",
92
+ "text": "Search Bots (i.e. Google, Bing, DuckDuckGo, Yandex, Baidu, Apple)"
93
  },
94
  {
95
  "value_key": "uptime",
102
  "summary": "Select Which Types Of Requests To Exclude",
103
  "description": "Deselect any requests that you don't want to appear in the traffic viewer."
104
  },
105
+ {
106
+ "key": "custom_exclusions",
107
+ "section": "section_traffic_options",
108
+ "default": [],
109
+ "type": "array",
110
+ "link_info": "",
111
+ "link_blog": "",
112
+ "name": "Custom Exclusions",
113
+ "summary": "Provide Custom Traffic Exclusions",
114
+ "description": "For each entry, if the text is present in either the User Agent or Page/Path, it will be excluded."
115
+ },
116
  {
117
  "key": "auto_clean",
118
  "section": "section_traffic_options",
src/config/feature-user_management.php CHANGED
@@ -1,187 +1,186 @@
1
  {
2
- "slug": "user_management",
3
- "properties": {
4
- "name": "User Management",
5
  "show_module_menu_item": true,
6
- "storage_key": "user_management",
7
- "tagline": "Control user sessions, duration, timeouts and account sharing",
8
- "show_central": true,
9
- "access_restricted": true,
10
- "premium": false,
11
- "has_custom_actions": true,
12
- "order": 40
 
 
13
  },
14
- "sections": [
15
  {
16
- "slug": "section_user_session_management",
17
- "primary": true,
18
- "primary": true,
19
- "title": "User Session Management",
20
  "title_short": "Session Options",
21
- "summary": [
22
  "Purpose - Allows you to better control user sessions on your site and expire idle sessions and prevent account sharing.",
23
  "Recommendation - Use of this feature is highly recommend."
24
  ]
25
  },
26
  {
27
- "slug": "section_passwords",
28
- "reqs" : {
29
  "php_min": "5.4",
30
- "wp_min": "4.4"
31
  },
32
- "title": "Password Policies",
33
  "title_short": "Password Policies",
34
- "summary": [
35
  "Purpose - Have full control over passwords used by users on the site.",
36
  "Recommendation - Use of this feature is highly recommend."
37
  ]
38
  },
39
  {
40
- "slug": "section_admin_login_notification",
41
- "title": "Admin Login Notification",
42
  "title_short": "Notifications",
43
- "summary": [
44
  "Purpose - So you can be made aware of when a WordPress administrator has logged into your site when you are not expecting it.",
45
  "Recommendation - Use of this feature is highly recommend."
46
  ]
47
  },
48
  {
49
- "slug": "section_enable_plugin_feature_user_accounts_management",
50
- "title": "Enable Module: User Management",
51
  "title_short": "Disable Module",
52
- "summary": [
53
  "Purpose - User Management offers real user sessions, finer control over user session time-out, and ensures users have logged-in in a correct manner.",
54
  "Recommendation - Keep the User Management feature turned on."
55
  ]
56
  },
57
  {
58
- "slug": "section_non_ui",
59
  "hidden": true
60
  }
61
  ],
62
- "options": [
63
  {
64
- "key": "enable_user_management",
65
- "section": "section_enable_plugin_feature_user_accounts_management",
66
- "default": "Y",
67
- "type": "checkbox",
68
- "link_info": "",
69
- "link_blog": "",
70
- "name": "Enable User Management",
71
- "summary": "Enable (or Disable) The User Management module",
72
  "description": "Un-Checking this option will completely disable the User Management module"
73
  },
74
  {
75
- "key": "enable_user_login_email_notification",
76
- "section": "section_admin_login_notification",
77
- "premium": true,
78
- "sensitive": false,
79
- "default": "N",
80
- "type": "checkbox",
81
- "link_info": "",
82
- "link_blog": "",
83
- "name": "User Login Notification Email",
84
- "summary": "Send Email Notification To Each User Upon Successful Login",
85
  "description": "A notification is sent to each user when a successful login occurs for their account."
86
  },
87
  {
88
- "key": "enable_admin_login_email_notification",
89
- "section": "section_admin_login_notification",
90
- "sensitive": true,
91
- "default": "",
92
- "type": "email",
93
- "link_info": "",
94
- "link_blog": "",
95
- "name": "Admin Login Notification Email",
96
- "summary": "Send An Notification Email When Administrator Logs In",
97
  "description": "If you would like to be notified every time an administrator user logs into this WordPress site, enter a notification email address. No email address - No Notification."
98
  },
99
  {
100
- "key": "session_timeout_interval",
101
- "section": "section_user_session_management",
102
- "default": 2,
103
- "type": "integer",
104
- "link_info": "",
105
- "link_blog": "",
106
- "name": "Session Timeout",
107
- "summary": "Specify How Many Days After Login To Automatically Force Re-Login",
108
  "description": "WordPress default is 2 days, or 14 days if you check the 'Remember Me' box."
109
  },
110
  {
111
- "key": "session_idle_timeout_interval",
112
- "section": "section_user_session_management",
113
- "default": 48,
114
- "type": "integer",
115
- "link_info": "",
116
- "link_blog": "",
117
- "name": "Idle Timeout",
118
- "summary": "Specify How Many Hours After Inactivity To Automatically Logout User",
119
  "description": "If the user is inactive for the number of hours specified, they will be forcefully logged out next time they return. Set this to '0' to turn off this option."
120
  },
121
  {
122
- "key": "session_lock_location",
123
- "section": "section_user_session_management",
124
- "default": "N",
125
- "type": "checkbox",
126
- "link_info": "",
127
- "link_blog": "",
128
- "name": "Lock To Location",
129
- "summary": "Locks A User Session To IP address",
130
  "description": "When selected, a session is restricted to the same IP address as when the user logged in. If a logged-in user's IP address changes, the session will be invalidated and they'll be forced to re-login to WordPress."
131
  },
132
  {
133
- "key": "session_username_concurrent_limit",
134
- "section": "section_user_session_management",
135
- "default": 0,
136
- "type": "integer",
137
- "link_info": "",
138
- "link_blog": "",
139
- "name": "Max Simultaneous Sessions",
140
- "summary": "Limit Simultaneous Sessions For The Same Username",
141
  "description": "The number provided here is the maximum number of simultaneous, distinct, sessions allowed for any given username. Use '0' for no limits."
142
  },
143
  {
144
- "key": "enable_password_policies",
145
- "section": "section_passwords",
146
- "type": "checkbox",
147
- "default": "N",
148
- "link_info": "https://icwp.io/c4",
149
- "link_blog": "",
150
- "name": "Enable Password Policies",
151
- "summary": "Enable The Password Policies Below",
152
  "description": "Turn on/off all password policies."
153
  },
154
  {
155
- "key": "pass_prevent_pwned",
156
- "section": "section_passwords",
157
- "type": "checkbox",
158
- "default": "Y",
159
- "link_info": "https://icwp.io/by",
160
- "link_blog": "",
161
- "name": "Prevent Pwned Passwords",
162
- "summary": "Prevent Use Of Pwned Passwords",
163
  "description": "Prevents users from using any passwords found on the public available list of pwned passwords."
164
  },
165
  {
166
- "key": "pass_min_length",
167
- "premium": true,
168
- "section": "section_passwords",
169
- "premium": true,
170
- "type": "integer",
171
- "default": "12",
172
- "link_info": "",
173
- "link_blog": "",
174
- "name": "Minimum Length",
175
- "summary": "Minimum Password Length",
176
  "description": "All passwords that a user sets must be at least this many characters in length."
177
  },
178
  {
179
- "key": "pass_min_strength",
180
- "premium": true,
181
- "section": "section_passwords",
182
- "premium": true,
183
  "type": "select",
184
- "default": "4",
185
  "value_options": [
186
  {
187
  "value_key": "0",
@@ -204,36 +203,34 @@
204
  "text": "Very Strong"
205
  }
206
  ],
207
- "link_info": "",
208
- "link_blog": "",
209
- "name": "Minimum Strength",
210
- "summary": "Minimum Password Strength",
211
- "description": "All passwords that a user sets must meet this minimum strength."
212
  },
213
  {
214
- "key": "pass_force_existing",
215
- "premium": true,
216
- "section": "section_passwords",
217
- "premium": true,
218
- "type": "checkbox",
219
- "default": "N",
220
- "link_info": "",
221
- "link_blog": "",
222
- "name": "Apply To Existing Users",
223
- "summary": "Apply Password Policies To Existing Users and Their Passwords",
224
  "description": "Forces existing users to update their passwords if they don't meet requirements, after they next login ."
225
  },
226
  {
227
- "key": "pass_expire",
228
- "premium": true,
229
- "section": "section_passwords",
230
- "premium": true,
231
- "type": "integer",
232
- "default": "60",
233
- "link_info": "",
234
- "link_blog": "",
235
- "name": "Password Expiration",
236
- "summary": "Passwords Expire After This Many Days",
237
  "description": "Users will be forced to reset their passwords after the number of days specified."
238
  },
239
  {
@@ -255,8 +252,8 @@
255
  }
256
  ],
257
  "definitions": {
258
- "cron_name_sessionscleanup": "sessionscleanup",
259
  "pwned_api_url_password_single": "https://api.pwnedpasswords.com/pwnedpassword/",
260
- "pwned_api_url_password_range": "https://api.pwnedpasswords.com/range/"
261
  }
262
  }
1
  {
2
+ "slug": "user_management",
3
+ "properties": {
4
+ "name": "User Management",
5
  "show_module_menu_item": true,
6
+ "storage_key": "user_management",
7
+ "tagline": "Control user sessions, duration, timeouts and account sharing",
8
+ "show_central": true,
9
+ "access_restricted": true,
10
+ "premium": false,
11
+ "has_custom_actions": true,
12
+ "run_if_whitelisted": false,
13
+ "run_if_verified_bot": false,
14
+ "order": 40
15
  },
16
+ "sections": [
17
  {
18
+ "slug": "section_user_session_management",
19
+ "primary": true,
20
+ "title": "User Session Management",
 
21
  "title_short": "Session Options",
22
+ "summary": [
23
  "Purpose - Allows you to better control user sessions on your site and expire idle sessions and prevent account sharing.",
24
  "Recommendation - Use of this feature is highly recommend."
25
  ]
26
  },
27
  {
28
+ "slug": "section_passwords",
29
+ "reqs": {
30
  "php_min": "5.4",
31
+ "wp_min": "4.4"
32
  },
33
+ "title": "Password Policies",
34
  "title_short": "Password Policies",
35
+ "summary": [
36
  "Purpose - Have full control over passwords used by users on the site.",
37
  "Recommendation - Use of this feature is highly recommend."
38
  ]
39
  },
40
  {
41
+ "slug": "section_admin_login_notification",
42
+ "title": "Admin Login Notification",
43
  "title_short": "Notifications",
44
+ "summary": [
45
  "Purpose - So you can be made aware of when a WordPress administrator has logged into your site when you are not expecting it.",
46
  "Recommendation - Use of this feature is highly recommend."
47
  ]
48
  },
49
  {
50
+ "slug": "section_enable_plugin_feature_user_accounts_management",
51
+ "title": "Enable Module: User Management",
52
  "title_short": "Disable Module",
53
+ "summary": [
54
  "Purpose - User Management offers real user sessions, finer control over user session time-out, and ensures users have logged-in in a correct manner.",
55
  "Recommendation - Keep the User Management feature turned on."
56
  ]
57
  },
58
  {
59
+ "slug": "section_non_ui",
60
  "hidden": true
61
  }
62
  ],
63
+ "options": [
64
  {
65
+ "key": "enable_user_management",
66
+ "section": "section_enable_plugin_feature_user_accounts_management",
67
+ "default": "Y",
68
+ "type": "checkbox",
69
+ "link_info": "",
70
+ "link_blog": "",
71
+ "name": "Enable User Management",
72
+ "summary": "Enable (or Disable) The User Management module",
73
  "description": "Un-Checking this option will completely disable the User Management module"
74
  },
75
  {
76
+ "key": "enable_user_login_email_notification",
77
+ "section": "section_admin_login_notification",
78
+ "premium": true,
79
+ "sensitive": false,
80
+ "default": "N",
81
+ "type": "checkbox",
82
+ "link_info": "",
83
+ "link_blog": "",
84
+ "name": "User Login Notification Email",
85
+ "summary": "Send Email Notification To Each User Upon Successful Login",
86
  "description": "A notification is sent to each user when a successful login occurs for their account."
87
  },
88
  {
89
+ "key": "enable_admin_login_email_notification",
90
+ "section": "section_admin_login_notification",
91
+ "sensitive": true,
92
+ "default": "",
93
+ "type": "email",
94
+ "link_info": "",
95
+ "link_blog": "",
96
+ "name": "Admin Login Notification Email",
97
+ "summary": "Send An Notification Email When Administrator Logs In",
98
  "description": "If you would like to be notified every time an administrator user logs into this WordPress site, enter a notification email address. No email address - No Notification."
99
  },
100
  {
101
+ "key": "session_timeout_interval",
102
+ "section": "section_user_session_management",
103
+ "default": 2,
104
+ "type": "integer",
105
+ "link_info": "",
106
+ "link_blog": "",
107
+ "name": "Session Timeout",
108
+ "summary": "Specify How Many Days After Login To Automatically Force Re-Login",
109
  "description": "WordPress default is 2 days, or 14 days if you check the 'Remember Me' box."
110
  },
111
  {
112
+ "key": "session_idle_timeout_interval",
113
+ "section": "section_user_session_management",
114
+ "default": 48,
115
+ "type": "integer",
116
+ "link_info": "",
117
+ "link_blog": "",
118
+ "name": "Idle Timeout",
119
+ "summary": "Specify How Many Hours After Inactivity To Automatically Logout User",
120
  "description": "If the user is inactive for the number of hours specified, they will be forcefully logged out next time they return. Set this to '0' to turn off this option."
121
  },
122
  {
123
+ "key": "session_lock_location",
124
+ "section": "section_user_session_management",
125
+ "default": "N",
126
+ "type": "checkbox",
127
+ "link_info": "",
128
+ "link_blog": "",
129
+ "name": "Lock To Location",
130
+ "summary": "Locks A User Session To IP address",
131
  "description": "When selected, a session is restricted to the same IP address as when the user logged in. If a logged-in user's IP address changes, the session will be invalidated and they'll be forced to re-login to WordPress."
132
  },
133
  {
134
+ "key": "session_username_concurrent_limit",
135
+ "section": "section_user_session_management",
136
+ "default": 0,
137
+ "type": "integer",
138
+ "link_info": "",
139
+ "link_blog": "",
140
+ "name": "Max Simultaneous Sessions",
141
+ "summary": "Limit Simultaneous Sessions For The Same Username",
142
  "description": "The number provided here is the maximum number of simultaneous, distinct, sessions allowed for any given username. Use '0' for no limits."
143
  },
144
  {
145
+ "key": "enable_password_policies",
146
+ "section": "section_passwords",
147
+ "type": "checkbox",
148
+ "default": "N",
149
+ "link_info": "https://icwp.io/c4",
150
+ "link_blog": "",
151
+ "name": "Enable Password Policies",
152
+ "summary": "Enable The Password Policies Below",
153
  "description": "Turn on/off all password policies."
154
  },
155
  {
156
+ "key": "pass_prevent_pwned",
157
+ "section": "section_passwords",
158
+ "type": "checkbox",
159
+ "default": "Y",
160
+ "link_info": "https://icwp.io/by",
161
+ "link_blog": "",
162
+ "name": "Prevent Pwned Passwords",
163
+ "summary": "Prevent Use Of Pwned Passwords",
164
  "description": "Prevents users from using any passwords found on the public available list of pwned passwords."
165
  },
166
  {
167
+ "key": "pass_min_length",
168
+ "section": "section_passwords",
169
+ "premium": true,
170
+ "type": "integer",
171
+ "default": "12",
172
+ "link_info": "",
173
+ "link_blog": "",
174
+ "name": "Minimum Length",
175
+ "summary": "Minimum Password Length",
 
176
  "description": "All passwords that a user sets must be at least this many characters in length."
177
  },
178
  {
179
+ "key": "pass_min_strength",
180
+ "section": "section_passwords",
181
+ "premium": true,
 
182
  "type": "select",
183
+ "default": "4",
184
  "value_options": [
185
  {
186
  "value_key": "0",
203
  "text": "Very Strong"
204
  }
205
  ],
206
+ "link_info": "",
207
+ "link_blog": "",
208
+ "name": "Minimum Strength",
209
+ "summary": "Minimum Password Strength",
210
+ "description": "All passwords that a user sets must meet this minimum strength."
211
  },
212
  {
213
+ "key": "pass_force_existing",
214
+ "section": "section_passwords",
215
+ "premium": true,
216
+ "type": "checkbox",
217
+ "default": "N",
218
+ "link_info": "",
219
+ "link_blog": "",
220
+ "name": "Apply To Existing Users",
221
+ "summary": "Apply Password Policies To Existing Users and Their Passwords",
 
222
  "description": "Forces existing users to update their passwords if they don't meet requirements, after they next login ."
223
  },
224
  {
225
+ "key": "pass_expire",
226
+ "section": "section_passwords",
227
+ "premium": true,
228
+ "type": "integer",
229
+ "default": "60",
230
+ "link_info": "",
231
+ "link_blog": "",
232
+ "name": "Password Expiration",
233
+ "summary": "Passwords Expire After This Many Days",
 
234
  "description": "Users will be forced to reset their passwords after the number of days specified."
235
  },
236
  {
252
  }
253
  ],
254
  "definitions": {
255
+ "cron_name_sessionscleanup": "sessionscleanup",
256
  "pwned_api_url_password_single": "https://api.pwnedpasswords.com/pwnedpassword/",
257
+ "pwned_api_url_password_range": "https://api.pwnedpasswords.com/range/"
258
  }
259
  }
src/features/admin_access_restriction.php CHANGED
@@ -67,7 +67,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
67
 
68
  if ( $this->checkAdminAccessKeySubmission() ) {
69
 
70
- if ( $this->setPermissionToSubmit( true ) ) {
71
  $aResponse[ 'success' ] = true;
72
  $aResponse[ 'html' ] = _wpsf__( 'Security Admin Access Key Accepted.' )
73
  .' '._wpsf__( 'Please wait' ).' ...';
@@ -93,30 +93,6 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
93
  );
94
  }
95
 
96
- /**
97
- * @return array
98
- */
99
- protected function ajaxExec_RestrictedAccess() {
100
- $aResponse = array();
101
-
102
- if ( $this->checkAdminAccessKeySubmission() ) {
103
-
104
- if ( $this->setPermissionToSubmit( true ) ) {
105
- $aResponse[ 'success' ] = true;
106
- $aResponse[ 'html' ] = _wpsf__( 'Security Admin Access Key Accepted.' )
107
- .' '._wpsf__( 'Please wait' ).' ...';
108
- }
109
- else {
110
- $aResponse[ 'html' ] = _wpsf__( 'Failed to process key - you may need to re-login to WordPress.' );
111
- }
112
- }
113
- else {
114
- $aResponse[ 'html' ] = $this->renderAdminAccessAjaxLoginForm( _wpsf__( 'Error - Invalid Key' ) );
115
- }
116
-
117
- return $aResponse;
118
- }
119
-
120
  /**
121
  * @param string $sMessage
122
  * @return string
@@ -231,13 +207,33 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
231
  return !empty( $sKey ) && strlen( $sKey ) == 32;
232
  }
233
 
 
 
 
 
 
 
 
234
  /**
235
  */
236
  protected function doExtraSubmitProcessing() {
237
- // We should only use setPermissionToSubmit() here, before any headers elsewhere are sent out.
238
- if ( $this->isAccessKeyRequest() ) {
239
- if ( $this->checkAdminAccessKeySubmission() ) {
240
- $this->setPermissionToSubmit( true );
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  }
242
  }
243
  }
@@ -286,14 +282,14 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
286
  }
287
 
288
  /**
289
- * @param bool $bPermission
290
  * @return bool
291
  */
292
- public function setPermissionToSubmit( $bPermission = false ) {
293
- $oSession = $this->getSession();
294
- $oUpdater = $this->getSessionsProcessor()
295
- ->getQueryUpdater();
296
- return $bPermission ? $oUpdater->startSecurityAdmin( $oSession ) : $oUpdater->terminateSecurityAdmin( $oSession );
297
  }
298
 
299
  /**
@@ -339,11 +335,40 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
339
  'name_company' => $this->getOpt( 'wl_companyname' ),
340
  'description' => $this->getOpt( 'wl_description' ),
341
  'url_home' => $this->getOpt( 'wl_homeurl' ),
342
- 'url_icon' => $this->getOpt( 'wl_menuiconurl' ),
343
- 'url_dashboardlogourl' => $this->getOpt( 'wl_dashboardlogourl' ),
 
344
  );
345
  }
346
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  /**
348
  * @return bool
349
  */
@@ -609,7 +634,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
609
  $sName = _wpsf__( 'Menu Icon' );
610
  $sSummary = _wpsf__( 'Menu Icon URL' );
611
  $sDescription = _wpsf__( 'The URL of the icon to display in the menu.' )
612
- .' '.sprintf( _wpsf__( 'The %s should measure %s.' ), _wpsf__( 'icon' ), '32px x 32px' );
613
  break;
614
  case 'wl_dashboardlogourl' :
615
  $sName = _wpsf__( 'Dashboard Logo' );
@@ -617,6 +642,11 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
617
  $sDescription = _wpsf__( 'The URL of the logo to display in the admin pages.' )
618
  .' '.sprintf( _wpsf__( 'The %s should measure %s.' ), _wpsf__( 'logo' ), '128px x 128px' );
619
  break;
 
 
 
 
 
620
 
621
  default:
622
  throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
@@ -635,7 +665,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
635
 
636
  if ( $this->getAccessKeyHash() == self::HASH_DELETE ) {
637
  $this->clearAdminAccessKey()
638
- ->setPermissionToSubmit( false );
639
  }
640
 
641
  // Restricting Activate Plugins also means restricting the rest.
@@ -671,12 +701,5 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
671
  array_unique( array_merge( $aPostRestrictions, array( 'create', 'publish', 'delete' ) ) )
672
  );
673
  }
674
-
675
- if ( !filter_var( $this->getOpt( 'wl_menuiconurl' ), FILTER_VALIDATE_URL ) ) {
676
- $this->setOpt( 'wl_menuiconurl', '' );
677
- }
678
- if ( !filter_var( $this->getOpt( 'wl_dashboardlogourl' ), FILTER_VALIDATE_URL ) ) {
679
- $this->setOpt( 'wl_dashboardlogourl', '' );
680
- }
681
  }
682
  }
67
 
68
  if ( $this->checkAdminAccessKeySubmission() ) {
69
 
70
+ if ( $this->setSecurityAdminStatusOnOff( true ) ) {
71
  $aResponse[ 'success' ] = true;
72
  $aResponse[ 'html' ] = _wpsf__( 'Security Admin Access Key Accepted.' )
73
  .' '._wpsf__( 'Please wait' ).' ...';
93
  );
94
  }
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  /**
97
  * @param string $sMessage
98
  * @return string
207
  return !empty( $sKey ) && strlen( $sKey ) == 32;
208
  }
209
 
210
+ /**
211
+ * @return bool
212
+ */
213
+ public function isAdminAccessAdminUsersEnabled() {
214
+ return $this->isOpt( 'admin_access_restrict_admin_users', 'Y' );
215
+ }
216
+
217
  /**
218
  */
219
  protected function doExtraSubmitProcessing() {
220
+ if ( $this->isAccessKeyRequest() && $this->checkAdminAccessKeySubmission() ) {
221
+ $this->setSecurityAdminStatusOnOff( true );
222
+ }
223
+
224
+ // Verify whitelabel images
225
+ if ( $this->isWlEnabled() ) {
226
+ $aImages = array(
227
+ 'wl_menuiconurl',
228
+ 'wl_dashboardlogourl',
229
+ 'wl_login2fa_logourl',
230
+ );
231
+ $oDP = $this->loadDP();
232
+ $oOpts = $this->getOptionsVo();
233
+ foreach ( $aImages as $sKey ) {
234
+ if ( !$oDP->isValidUrl( $this->buildWlImageUrl( $sKey ) ) ) {
235
+ $oOpts->resetOptToDefault( $sKey );
236
+ }
237
  }
238
  }
239
  }
282
  }
283
 
284
  /**
285
+ * @param bool $bSetOn
286
  * @return bool
287
  */
288
+ public function setSecurityAdminStatusOnOff( $bSetOn = false ) {
289
+ $oUpdater = $this->getSessionsProcessor()->getQueryUpdater();
290
+ return $bSetOn ?
291
+ $oUpdater->startSecurityAdmin( $this->getSession() )
292
+ : $oUpdater->terminateSecurityAdmin( $this->getSession() );
293
  }
294
 
295
  /**
335
  'name_company' => $this->getOpt( 'wl_companyname' ),
336
  'description' => $this->getOpt( 'wl_description' ),
337
  'url_home' => $this->getOpt( 'wl_homeurl' ),
338
+ 'url_icon' => $this->buildWlImageUrl( 'wl_menuiconurl' ),
339
+ 'url_dashboardlogourl' => $this->buildWlImageUrl( 'wl_dashboardlogourl' ),
340
+ 'url_login2fa_logourl' => $this->buildWlImageUrl( 'wl_login2fa_logourl' ),
341
  );
342
  }
343
 
344
+ /**
345
+ * We cater for 3 options:
346
+ * Full URL
347
+ * Relative path URL: i.e. starts with /
348
+ * Or Plugin image URL i.e. doesn't start with HTTP or /
349
+ * @param string $sKey
350
+ * @return string
351
+ */
352
+ private function buildWlImageUrl( $sKey ) {
353
+ $oDp = $this->loadDP();
354
+ $oOpts = $this->getOptionsVo();
355
+
356
+ $sLogoUrl = $this->getOpt( $sKey );
357
+ if ( empty( $sLogoUrl ) ) {
358
+ $oOpts->resetOptToDefault( $sKey );
359
+ $sLogoUrl = $this->getOpt( $sKey );
360
+ }
361
+ if ( !empty( $sLogoUrl ) && !$oDp->isValidUrl( $sLogoUrl ) && strpos( $sLogoUrl, '/' ) !== 0 ) {
362
+ $sLogoUrl = $this->getConn()->getPluginUrl_Image( $sLogoUrl );
363
+ if ( empty( $sLogoUrl ) ) {
364
+ $oOpts->resetOptToDefault( $sKey );
365
+ $sLogoUrl = $this->getConn()->getPluginUrl_Image( $this->getOpt( $sKey ) );
366
+ }
367
+ }
368
+
369
+ return $sLogoUrl;
370
+ }
371
+
372
  /**
373
  * @return bool
374
  */
634
  $sName = _wpsf__( 'Menu Icon' );
635
  $sSummary = _wpsf__( 'Menu Icon URL' );
636
  $sDescription = _wpsf__( 'The URL of the icon to display in the menu.' )
637
+ .' '.sprintf( _wpsf__( 'The %s should measure %s.' ), _wpsf__( 'icon' ), '16px x 16px' );
638
  break;
639
  case 'wl_dashboardlogourl' :
640
  $sName = _wpsf__( 'Dashboard Logo' );
642
  $sDescription = _wpsf__( 'The URL of the logo to display in the admin pages.' )
643
  .' '.sprintf( _wpsf__( 'The %s should measure %s.' ), _wpsf__( 'logo' ), '128px x 128px' );
644
  break;
645
+ case 'wl_login2fa_logourl' :
646
+ $sName = _wpsf__( '2FA Login Logo URL' );
647
+ $sSummary = _wpsf__( '2FA Login Logo URL' );
648
+ $sDescription = _wpsf__( 'The URL of the logo to display on the Two-Factor Authentication login page.' );
649
+ break;
650
 
651
  default:
652
  throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
665
 
666
  if ( $this->getAccessKeyHash() == self::HASH_DELETE ) {
667
  $this->clearAdminAccessKey()
668
+ ->setSecurityAdminStatusOnOff( false );
669
  }
670
 
671
  // Restricting Activate Plugins also means restricting the rest.
701
  array_unique( array_merge( $aPostRestrictions, array( 'create', 'publish', 'delete' ) ) )
702
  );
703
  }
 
 
 
 
 
 
 
704
  }
705
  }
src/features/autoupdates.php CHANGED
@@ -88,7 +88,7 @@ class ICWP_WPSF_FeatureHandler_Autoupdates extends ICWP_WPSF_FeatureHandler_Base
88
  }
89
 
90
  /**
91
- * @param $sPluginFile
92
  * @return bool
93
  */
94
  public function isPluginSetToAutoupdate( $sPluginFile ) {
88
  }
89
 
90
  /**
91
+ * @param string $sPluginFile
92
  * @return bool
93
  */
94
  public function isPluginSetToAutoupdate( $sPluginFile ) {
src/features/base.php CHANGED
@@ -1800,6 +1800,7 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
1800
  }
1801
 
1802
  /**
 
1803
  * @return ICWP_WPSF_Plugin_Controller
1804
  */
1805
  static public function getController() {
1800
  }
1801
 
1802
  /**
1803
+ * @deprecated
1804
  * @return ICWP_WPSF_Plugin_Controller
1805
  */
1806
  static public function getController() {
src/features/base_wpsf.php CHANGED
@@ -13,6 +13,11 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
13
  */
14
  static protected $oSessProcessor;
15
 
 
 
 
 
 
16
  /**
17
  * @return ICWP_WPSF_Processor_Sessions
18
  */
@@ -32,7 +37,7 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
32
  * @return bool
33
  */
34
  public function hasSession() {
35
- return !is_null( $this->getSession() );
36
  }
37
 
38
  public function insertCustomJsVars() {
@@ -58,9 +63,10 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
58
  * @return int
59
  */
60
  protected function getSecAdminTimeLeft() {
61
- return $this->getController()
62
- ->getModule( 'admin_access_restriction' )
63
- ->getSecAdminTimeLeft();
 
64
  }
65
 
66
  /**
@@ -243,7 +249,9 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
243
  * @return bool
244
  */
245
  protected function isReadyToExecute() {
246
- return ( $this->getOptionsVo()->isModuleWhitelistExempt() || !$this->isVisitorWhitelisted() )
 
 
247
  && parent::isReadyToExecute();
248
  }
249
 
@@ -251,16 +259,45 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
251
  * @return bool
252
  */
253
  protected function isVisitorWhitelisted() {
254
- return apply_filters( $this->prefix( 'visitor_is_whitelisted' ), false );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  }
256
 
257
  /**
258
  * @return bool
259
  */
260
  public function isXmlrpcBypass() {
261
- return $this->getConn()
262
- ->getModule( 'plugin' )
263
- ->isXmlrpcBypass();
 
264
  }
265
 
266
  /**
13
  */
14
  static protected $oSessProcessor;
15
 
16
+ /**
17
+ * @var bool
18
+ */
19
+ static protected $bIsVerifiedBot;
20
+
21
  /**
22
  * @return ICWP_WPSF_Processor_Sessions
23
  */
37
  * @return bool
38
  */
39
  public function hasSession() {
40
+ return ( $this->getSession() instanceof ICWP_WPSF_SessionVO );
41
  }
42
 
43
  public function insertCustomJsVars() {
63
  * @return int
64
  */
65
  protected function getSecAdminTimeLeft() {
66
+ /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
67
+ $oFO = $this->getConn()
68
+ ->getModule( 'admin_access_restriction' );
69
+ return $oFO->getSecAdminTimeLeft();
70
  }
71
 
72
  /**
249
  * @return bool
250
  */
251
  protected function isReadyToExecute() {
252
+ $oOpts = $this->getOptionsVo();
253
+ return ( $oOpts->isModuleRunIfWhitelisted() || !$this->isVisitorWhitelisted() )
254
+ && ( $oOpts->isModuleRunIfVerifiedBot() || !$this->isVerifiedBot() )
255
  && parent::isReadyToExecute();
256
  }
257
 
259
  * @return bool
260
  */
261
  protected function isVisitorWhitelisted() {
262
+ /** @var ICWP_WPSF_Processor_Ips $oPro */
263
+ $oPro = $this->getConn()
264
+ ->getModule( 'ips' )
265
+ ->getProcessor();
266
+ return $oPro->isCurrentIpWhitelisted();
267
+ }
268
+
269
+ /**
270
+ * Only test for bots that we can actually verify based on IP, hostname
271
+ * @return bool
272
+ */
273
+ public function isVerifiedBot() {
274
+ if ( !isset( self::$bIsVerifiedBot ) ) {
275
+ $oSp = $this->loadServiceProviders();
276
+
277
+ $sIp = $this->loadIpService()->getRequestIp();
278
+ $sAgent = (string)$this->loadDP()->server( 'HTTP_USER_AGENT' );
279
+ if ( empty( $sAgent ) ) {
280
+ $sAgent = 'Unknown';
281
+ }
282
+ self::$bIsVerifiedBot = $oSp->isIp_GoogleBot( $sIp, $sAgent )
283
+ || $oSp->isIp_BingBot( $sIp, $sAgent )
284
+ || $oSp->isIp_AppleBot( $sIp, $sAgent )
285
+ || $oSp->isIp_YahooBot( $sIp, $sAgent )
286
+ || $oSp->isIp_DuckDuckGoBot( $sIp, $sAgent )
287
+ || $oSp->isIp_YandexBot( $sIp, $sAgent )
288
+ || $oSp->isIp_BaiduBot( $sIp, $sAgent );
289
+ }
290
+ return self::$bIsVerifiedBot;
291
  }
292
 
293
  /**
294
  * @return bool
295
  */
296
  public function isXmlrpcBypass() {
297
+ /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
298
+ $oFO = $this->getConn()
299
+ ->getModule( 'plugin' );
300
+ return $oFO->isXmlrpcBypass();
301
  }
302
 
303
  /**
src/features/firewall.php CHANGED
@@ -11,9 +11,17 @@ class ICWP_WPSF_FeatureHandler_Firewall extends ICWP_WPSF_FeatureHandler_BaseWps
11
  /**
12
  * @return array
13
  */
14
- public function getPageParamWhitelist() {
15
- $aPageWhitelist = $this->getOpt( 'page_params_whitelist', array() );
16
- return is_array( $aPageWhitelist ) ? $aPageWhitelist : array();
 
 
 
 
 
 
 
 
17
  }
18
 
19
  /**
11
  /**
12
  * @return array
13
  */
14
+ public function getDefaultWhitelist() {
15
+ $aW = $this->getDef( 'default_whitelist' );
16
+ return is_array( $aW ) ? $aW : array();
17
+ }
18
+
19
+ /**
20
+ * @return array
21
+ */
22
+ public function getCustomWhitelist() {
23
+ $aW = $this->getOpt( 'page_params_whitelist', array() );
24
+ return is_array( $aW ) ? $aW : array();
25
  }
26
 
27
  /**
src/features/hack_protect.php CHANGED
@@ -12,18 +12,6 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
12
  $this->setCustomCronSchedules();
13
  }
14
 
15
- /**
16
- */
17
- protected function updateHandler() {
18
- if ( $this->getConn()->getVersion() == '6.9.3' ) {
19
- /** @var ICWP_WPSF_Processor_HackProtect $oP */
20
- $oP = $this->getProcessor();
21
- $this->setPtgLastBuildAt( 0 );
22
- $oP->getSubProcessorGuard()
23
- ->deleteStores();
24
- }
25
- }
26
-
27
  /**
28
  * @param array $aAjaxResponse
29
  * @return array
@@ -569,7 +557,7 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
569
  public function insertCustomJsVars() {
570
  parent::insertCustomJsVars();
571
 
572
- if ( $this->loadWp()->getCurrentPage() == 'plugins.php' && $this->isPtgReinstallLinks() ) {
573
  wp_localize_script(
574
  $this->prefix( 'global-plugin' ),
575
  'icwp_wpsf_vars_hp',
12
  $this->setCustomCronSchedules();
13
  }
14
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  /**
16
  * @param array $aAjaxResponse
17
  * @return array
557
  public function insertCustomJsVars() {
558
  parent::insertCustomJsVars();
559
 
560
+ if ( $this->loadWp()->isCurrentPage( 'plugins.php' ) && $this->isPtgReinstallLinks() ) {
561
  wp_localize_script(
562
  $this->prefix( 'global-plugin' ),
563
  'icwp_wpsf_vars_hp',
src/features/license.php CHANGED
@@ -33,12 +33,13 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
33
  $sExpiresAt = 'n/a';
34
  }
35
 
 
36
  $aLicenseTableVars = array(
37
  'product_name' => $this->getLicenseItemName(),
38
- 'license_active' => $this->hasValidWorkingLicense() ? 'Active' : 'Not Active',
39
  'license_expires' => $sExpiresAt,
40
  'license_email' => $oCurrent->getCustomerEmail(),
41
- 'last_checked' => $oWp->getTimeStampForDisplay( $oCurrent->getLastRequestAt() ),
42
  'last_errors' => $this->hasLastErrors() ? $this->getLastErrors() : ''
43
  );
44
  if ( !$this->isKeyless() ) {
@@ -286,7 +287,7 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
286
  $oLookupLicense = $this->lookupOfficialLicense();
287
  if ( $oLookupLicense->isValid() ) {
288
  $oCurrent = $oLookupLicense;
289
- $oLookupLicense->updateLastVerifiedAt();
290
  $this->activateLicense()
291
  ->clearLastErrors();
292
  $oPro->addToAuditEntry( 'Pro License check succeeded.', 1, 'license_check_success' );
@@ -333,7 +334,8 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
333
  */
334
  protected function activateLicense() {
335
  if ( !$this->isLicenseActive() ) {
336
- $this->setOpt( 'license_activated_at', $this->loadLicense()->getLastRequestAt() );
 
337
  }
338
  return $this;
339
  }
33
  $sExpiresAt = 'n/a';
34
  }
35
 
36
+ $nLastReqAt = $oCurrent->getLastRequestAt();
37
  $aLicenseTableVars = array(
38
  'product_name' => $this->getLicenseItemName(),
39
+ 'license_active' => $this->hasValidWorkingLicense() ? _wpsf__( 'Active' ) : _wpsf__( 'Not Active' ),
40
  'license_expires' => $sExpiresAt,
41
  'license_email' => $oCurrent->getCustomerEmail(),
42
+ 'last_checked' => empty( $nLastReqAt ) ? _wpsf__( 'Never' ) : $oWp->getTimeStampForDisplay( $nLastReqAt ),
43
  'last_errors' => $this->hasLastErrors() ? $this->getLastErrors() : ''
44
  );
45
  if ( !$this->isKeyless() ) {
287
  $oLookupLicense = $this->lookupOfficialLicense();
288
  if ( $oLookupLicense->isValid() ) {
289
  $oCurrent = $oLookupLicense;
290
+ $oLookupLicense->updateLastVerifiedAt( true );
291
  $this->activateLicense()
292
  ->clearLastErrors();
293
  $oPro->addToAuditEntry( 'Pro License check succeeded.', 1, 'license_check_success' );
334
  */
335
  protected function activateLicense() {
336
  if ( !$this->isLicenseActive() ) {
337
+ $nAt = $this->loadLicense()->getLastRequestAt();
338
+ $this->setOptAt( 'license_activated_at', $nAt > 0 ? $nAt : null );
339
  }
340
  return $this;
341
  }
src/features/login_protect.php CHANGED
@@ -8,20 +8,6 @@ require_once( dirname( __FILE__ ).'/base_wpsf.php' );
8
 
9
  class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_BaseWpsf {
10
 
11
- /**
12
- * TODO remove
13
- */
14
- protected function updateHandler() {
15
- if ( $this->getConn()->getVersion() == '6.9.4' ) {
16
- if ( $this->getIfCanSendEmailVerified() && $this->isEmailAuthenticationOptionOn() ) {
17
- $aRoles = $this->getEmail2FaRoles();
18
- if ( count( $aRoles ) == 1 && in_array( 'subscriber', $aRoles ) ) {
19
- $this->getOptionsVo()->resetOptToDefault( 'two_factor_auth_user_roles' );
20
- }
21
- }
22
- }
23
- }
24
-
25
  /**
26
  * A action added to WordPress 'init' hook
27
  */
@@ -196,7 +182,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
196
  /**
197
  * @return bool
198
  */
199
- public function getIsCustomLoginPathEnabled() {
200
  $sPath = $this->getCustomLoginPath();
201
  return !empty( $sPath );
202
  }
@@ -320,7 +306,14 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
320
  /**
321
  * @return bool
322
  */
323
- public function getIsEnabledGoogleAuthenticator() {
 
 
 
 
 
 
 
324
  return $this->isOpt( 'enable_google_authenticator', 'Y' );
325
  }
326
 
@@ -368,7 +361,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
368
  * @return bool
369
  */
370
  public function isCooldownEnabled() {
371
- return $this->getOpt( 'login_limit_interval' ) > 0;
372
  }
373
 
374
  /**
@@ -522,6 +515,82 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
522
  return !empty( $sAppId ) && !empty( $sApiKey );
523
  }
524
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
  /**
526
  * @param array $aOptionsParams
527
  * @return array
@@ -653,6 +722,12 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
653
  $sDescription = _wpsf__( 'Enter the number of days a user can by-pass future MFA after a successful MFA-login. 0 to disable.' );
654
  break;
655
 
 
 
 
 
 
 
656
  case 'enable_google_authenticator' :
657
  $sName = sprintf( _wpsf__( 'Enable %s' ), _wpsf__( 'Google Authenticator' ) );
658
  $sSummary = _wpsf__( 'Allow Users To Use Google Authenticator' );
8
 
9
  class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_BaseWpsf {
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  /**
12
  * A action added to WordPress 'init' hook
13
  */
182
  /**
183
  * @return bool
184
  */
185
+ public function isCustomLoginPathEnabled() {
186
  $sPath = $this->getCustomLoginPath();
187
  return !empty( $sPath );
188
  }
306
  /**
307
  * @return bool
308
  */
309
+ public function isEnabledBackupCodes() {
310
+ return $this->isPremium() && $this->isOpt( 'allow_backupcodes', 'Y' );
311
+ }
312
+
313
+ /**
314
+ * @return bool
315
+ */
316
+ public function isEnabledGoogleAuthenticator() {
317
  return $this->isOpt( 'enable_google_authenticator', 'Y' );
318
  }
319
 
361
  * @return bool
362
  */
363
  public function isCooldownEnabled() {
364
+ return (int)$this->getOpt( 'login_limit_interval' ) > 0;
365
  }
366
 
367
  /**
515
  return !empty( $sAppId ) && !empty( $sApiKey );
516
  }
517
 
518
+ /**
519
+ * @param array $aAjaxResponse
520
+ * @return array
521
+ */
522
+ public function handleAuthAjax( $aAjaxResponse ) {
523
+
524
+ if ( empty( $aAjaxResponse ) ) {
525
+ switch ( $this->loadDP()->request( 'exec' ) ) {
526
+
527
+ case 'gen_backup_codes':
528
+ $aAjaxResponse = $this->ajaxExec_GenBackupCodes();
529
+ break;
530
+
531
+ case 'del_backup_codes':
532
+ $aAjaxResponse = $this->ajaxExec_DeleteBackupCodes();
533
+ break;
534
+
535
+ default:
536
+ break;
537
+ }
538
+ }
539
+ return parent::handleAuthAjax( $aAjaxResponse );
540
+ }
541
+
542
+ /**
543
+ * @return array
544
+ */
545
+ protected function ajaxExec_GenBackupCodes() {
546
+
547
+ /** @var ICWP_WPSF_Processor_LoginProtect $oPro */
548
+ $oPro = $this->loadProcessor();
549
+ $sPass = $oPro->getProcessorLoginIntent()
550
+ ->getProcessorBackupCodes()
551
+ ->resetSecret( $this->loadWpUsers()->getCurrentWpUser() );
552
+
553
+ foreach ( array( 20, 15, 10, 5 ) as $nPos ) {
554
+ $sPass = substr_replace( $sPass, '-', $nPos, 0 );
555
+ }
556
+
557
+ return array(
558
+ 'code' => $sPass,
559
+ 'success' => true
560
+ );
561
+ }
562
+
563
+ /**
564
+ * @return array
565
+ */
566
+ protected function ajaxExec_DeleteBackupCodes() {
567
+
568
+ /** @var ICWP_WPSF_Processor_LoginProtect $oPro */
569
+ $oPro = $this->loadProcessor();
570
+ $oPro->getProcessorLoginIntent()
571
+ ->getProcessorBackupCodes()
572
+ ->deleteSecret( $this->loadWpUsers()->getCurrentWpUser() );
573
+ $this->setFlashAdminNotice( _wpsf__( 'Multi-factor login backup code has been removed from your profile' ) );
574
+ return array(
575
+ 'success' => true
576
+ );
577
+ }
578
+
579
+ public function insertCustomJsVars() {
580
+ parent::insertCustomJsVars();
581
+
582
+ wp_localize_script(
583
+ $this->prefix( 'global-plugin' ),
584
+ 'icwp_wpsf_vars_lg',
585
+ array(
586
+ 'ajax_gen_backup_codes' => $this->getAjaxActionData( 'gen_backup_codes' ),
587
+ 'ajax_del_backup_codes' => $this->getAjaxActionData( 'del_backup_codes' ),
588
+ )
589
+ );
590
+ wp_enqueue_script( 'jquery-ui-dialog' );
591
+ wp_enqueue_style( 'wp-jquery-ui-dialog' );
592
+ }
593
+
594
  /**
595
  * @param array $aOptionsParams
596
  * @return array
722
  $sDescription = _wpsf__( 'Enter the number of days a user can by-pass future MFA after a successful MFA-login. 0 to disable.' );
723
  break;
724
 
725
+ case 'allow_backupcodes' :
726
+ $sName = _wpsf__( 'Allow Backup Codes' );
727
+ $sSummary = _wpsf__( 'Allow Users To Generate A Backup Code' );
728
+ $sDescription = _wpsf__( 'Allow users to generate a backup code that can be used to login if MFA factors are unavailable.' );
729
+ break;
730
+
731
  case 'enable_google_authenticator' :
732
  $sName = sprintf( _wpsf__( 'Enable %s' ), _wpsf__( 'Google Authenticator' ) );
733
  $sSummary = _wpsf__( 'Allow Users To Use Google Authenticator' );
src/features/plugin.php CHANGED
@@ -173,6 +173,9 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
173
  $aAjaxResponse = $this->ajaxExec_SetPluginTrackingPerm();
174
  }
175
  break;
 
 
 
176
  }
177
  }
178
  return parent::handleAjax( $aAjaxResponse );
@@ -223,6 +226,25 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
223
  return array( 'success' => true );
224
  }
225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  /**
227
  * @return array
228
  */
@@ -711,6 +733,29 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
711
  return $this->prefixOptionKey( $this->getDef( 'db_notes_name' ) );
712
  }
713
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
714
  /**
715
  * @param array $aOptionsParams
716
  * @return array
@@ -919,6 +964,13 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
919
  return $aOptionsParams;
920
  }
921
 
 
 
 
 
 
 
 
922
  /**
923
  * Kept just in-case.
924
  */
173
  $aAjaxResponse = $this->ajaxExec_SetPluginTrackingPerm();
174
  }
175
  break;
176
+ case 'send_deactivate_survey':
177
+ $aAjaxResponse = $this->ajaxExec_SendDeactivateSurvey();
178
+ break;
179
  }
180
  }
181
  return parent::handleAjax( $aAjaxResponse );
226
  return array( 'success' => true );
227
  }
228
 
229
+ /**
230
+ * @return array
231
+ */
232
+ public function ajaxExec_SendDeactivateSurvey() {
233
+ $aResults = array();
234
+ foreach ( $_POST as $sKey => $sValue ) {
235
+ if ( strpos( $sKey, 'reason_' ) === 0 ) {
236
+ $aResults[] = str_replace( 'reason_', '', $sKey ).': '.$sValue;
237
+ }
238
+ }
239
+ $this->getEmailProcessor()
240
+ ->send(
241
+ $this->getSurveyEmail(),
242
+ 'Shield Deactivation Survey',
243
+ implode( "\n<br/>", $aResults )
244
+ );
245
+ return array( 'success' => true );
246
+ }
247
+
248
  /**
249
  * @return array
250
  */
733
  return $this->prefixOptionKey( $this->getDef( 'db_notes_name' ) );
734
  }
735
 
736
+ public function insertCustomJsVars() {
737
+ parent::insertCustomJsVars();
738
+
739
+ if ( $this->loadWp()->isCurrentPage( 'plugins.php' ) ) {
740
+ $sFile = $this->getConn()->getPluginBaseFile();
741
+ wp_localize_script(
742
+ $this->prefix( 'global-plugin' ),
743
+ 'icwp_wpsf_vars_plugin',
744
+ array(
745
+ 'file' => $sFile,
746
+ 'ajax' => array(
747
+ 'send_deactivate_survey' => $this->getAjaxActionData( 'send_deactivate_survey' ),
748
+ ),
749
+ 'hrefs' => array(
750
+ 'deactivate' => $this->loadWpPlugins()->getUrl_Deactivate( $sFile ),
751
+ ),
752
+ )
753
+ );
754
+ wp_enqueue_script( 'jquery-ui-dialog' ); // jquery and jquery-ui should be dependencies, didn't check though...
755
+ wp_enqueue_style( 'wp-jquery-ui-dialog' );
756
+ }
757
+ }
758
+
759
  /**
760
  * @param array $aOptionsParams
761
  * @return array
964
  return $aOptionsParams;
965
  }
966
 
967
+ /**
968
+ * @return string
969
+ */
970
+ private function getSurveyEmail() {
971
+ return base64_decode( $this->getDef( 'survey_email' ) );
972
+ }
973
+
974
  /**
975
  * Kept just in-case.
976
  */
src/features/traffic.php CHANGED
@@ -45,6 +45,12 @@ class ICWP_WPSF_FeatureHandler_Traffic extends ICWP_WPSF_FeatureHandler_BaseWpsf
45
  ->cleanupDatabase();
46
 
47
  $this->setOpt( 'autodisable_at', $this->isAutoDisable() ? $this->loadDP()->time() + WEEK_IN_SECONDS : 0 );
 
 
 
 
 
 
48
  }
49
 
50
  /**
@@ -90,6 +96,14 @@ class ICWP_WPSF_FeatureHandler_Traffic extends ICWP_WPSF_FeatureHandler_BaseWpsf
90
  return is_array( $aEx ) ? $aEx : array();
91
  }
92
 
 
 
 
 
 
 
 
 
93
  /**
94
  * @return int
95
  */
@@ -497,6 +511,14 @@ class ICWP_WPSF_FeatureHandler_Traffic extends ICWP_WPSF_FeatureHandler_BaseWpsf
497
  .'<br/>'._wpsf__( 'If a request matches any exclusion rule, it will not show on the traffic viewer.' );
498
  break;
499
 
 
 
 
 
 
 
 
 
500
  case 'auto_clean' :
501
  $sName = _wpsf__( 'Auto Expiry Cleaning' );
502
  $sSummary = _wpsf__( 'Enable Traffic Log Auto Expiry' );
45
  ->cleanupDatabase();
46
 
47
  $this->setOpt( 'autodisable_at', $this->isAutoDisable() ? $this->loadDP()->time() + WEEK_IN_SECONDS : 0 );
48
+
49
+ $aExcls = $this->getCustomExclusions();
50
+ foreach ( $aExcls as &$sExcl ) {
51
+ $sExcl = trim( esc_js( $sExcl ) );
52
+ }
53
+ $this->setOpt( 'custom_exclusions', array_filter( $aExcls ) );
54
  }
55
 
56
  /**
96
  return is_array( $aEx ) ? $aEx : array();
97
  }
98
 
99
+ /**
100
+ * @return array
101
+ */
102
+ public function getCustomExclusions() {
103
+ $aEx = $this->getOpt( 'custom_exclusions' );
104
+ return is_array( $aEx ) ? $aEx : array();
105
+ }
106
+
107
  /**
108
  * @return int
109
  */
511
  .'<br/>'._wpsf__( 'If a request matches any exclusion rule, it will not show on the traffic viewer.' );
512
  break;
513
 
514
+ case 'custom_exclusions' :
515
+ $sName = _wpsf__( 'Custom Exclusions' );
516
+ $sSummary = _wpsf__( 'Provide Custom Traffic Exclusions' );
517
+ $sDescription = _wpsf__( "For each entry, if the text is present in either the User Agent or request Path, it will be excluded." )
518
+ .'<br/>'._wpsf__( 'Take a new line for each entry.' )
519
+ .'<br/>'._wpsf__( 'Comparisons are case-insensitive.' );
520
+ break;
521
+
522
  case 'auto_clean' :
523
  $sName = _wpsf__( 'Auto Expiry Cleaning' );
524
  $sSummary = _wpsf__( 'Enable Traffic Log Auto Expiry' );
src/processors/admin_access_restriction.php CHANGED
@@ -16,18 +16,36 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
16
  public function run() {
17
  /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
18
  $oFO = $this->getMod();
19
- $oWp = $this->loadWp();
20
 
21
  add_filter( $oFO->prefix( 'has_permission_to_manage' ), array( $oFO, 'doCheckHasPermissionToSubmit' ) );
22
  add_filter( $oFO->prefix( 'has_permission_to_view' ), array( $oFO, 'doCheckHasPermissionToSubmit' ) );
23
 
24
- if ( !$oFO->isUpgrading() && !$oWp->isRequestUserLogin() ) {
25
  add_filter( 'pre_update_option', array( $this, 'blockOptionsSaves' ), 1, 3 );
26
  }
27
 
28
- if ( $oFO->isOpt( 'admin_access_restrict_admin_users', 'Y' ) ) {
29
- add_filter( 'user_has_cap', array( $this, 'restrictAdminUserChanges' ), 0, 3 );
30
- add_action( 'delete_user', array( $this, 'restrictAdminUserDelete' ), 0, 1 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
32
 
33
  $aPluginRestrictions = $oFO->getAdminAccessArea_Plugins();
@@ -48,10 +66,6 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
48
  if ( !$this->getController()->isThisPluginModuleRequest() ) {
49
  add_action( 'admin_footer', array( $this, 'printAdminAccessAjaxForm' ) );
50
  }
51
-
52
- if ( $oFO->isWlEnabled() ) {
53
- $this->runWhiteLabel();
54
- }
55
  }
56
 
57
  /**
@@ -102,42 +116,122 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
102
  return self::getController()->getHasPermissionToManage();
103
  }
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  /**
106
  * @param int $nId
107
  */
108
  public function restrictAdminUserDelete( $nId ) {
109
- if ( !$this->isSecurityAdmin() ) {
110
- $oWpUsers = $this->loadWpUsers();
111
- $oUser = $oWpUsers->getUserById( $nId );
112
- if ( $oUser && $oWpUsers->isUserAdmin( $oUser ) ) {
113
- $this->loadWp()
114
- ->wpDie( 'Sorry, deleting administrators is currently restricted to your Security Admin' );
115
- }
116
  }
117
  }
118
 
119
  /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  * @param array $aAllCaps
121
  * @param $cap
122
  * @param array $aArgs
123
  * @return array
124
  */
125
  public function restrictAdminUserChanges( $aAllCaps, $cap, $aArgs ) {
126
- // If we're registered with Admin Access we don't modify anything
127
- if ( $this->isSecurityAdmin() ) {
128
- return $aAllCaps;
129
- }
130
 
131
- $oWpUsers = $this->loadWpUsers();
132
- $oDp = $this->loadDP();
133
 
134
- /** @var string $sRequestedCapability */
135
- $sRequestedCapability = $aArgs[ 0 ];
136
- $aUserCapabilities = array( 'edit_users', 'create_users' );
137
-
138
- $bBlockCapability = false;
139
 
140
- if ( in_array( $sRequestedCapability, $aUserCapabilities ) ) {
 
141
 
142
  // Find the WP_User for the POST
143
  $oPostUser = false;
@@ -152,27 +246,26 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
152
  $oPostUser = $oWpUsers->getUserByUsername( $sPostUserlogin );
153
  }
154
 
155
- $sRequestRole = $oDp->FetchPost( 'role', '' );
156
 
157
  if ( $oPostUser instanceof WP_User ) {
158
  // editing an existing user other than yourself?
159
- if ( $oPostUser->user_login != $oWpUsers->getCurrentWpUser()->user_login ) {
160
 
161
  if ( $oWpUsers->isUserAdmin( $oPostUser ) || ( $sRequestRole == 'administrator' ) ) {
162
  $bBlockCapability = true;
163
  }
164
  }
165
  }
166
- else {
167
- //creating a new admin user?
168
  if ( $sRequestRole == 'administrator' ) {
169
  $bBlockCapability = true;
170
  }
171
  }
172
- }
173
 
174
- if ( $bBlockCapability ) {
175
- $aAllCaps[ $sRequestedCapability ] = false;
 
176
  }
177
 
178
  return $aAllCaps;
@@ -180,6 +273,7 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
180
 
181
  /**
182
  * @param array $aNoticeAttributes
 
183
  */
184
  public function addNotice_certain_options_restricted( $aNoticeAttributes ) {
185
  /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
@@ -217,14 +311,16 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
217
 
218
  /**
219
  * @param array $aNoticeAttributes
 
220
  */
221
  public function addNotice_admin_users_restricted( $aNoticeAttributes ) {
222
- /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
223
- $oFO = $this->getMod();
224
- if ( $oFO->doCheckHasPermissionToSubmit() ) {
225
  return;
226
  }
227
 
 
 
 
228
  $sCurrentPage = $this->loadWp()->getCurrentPage();
229
  if ( !in_array( $sCurrentPage, $this->getUserPagesToRestrict() ) ) {
230
  return;
@@ -317,10 +413,6 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
317
  * @return array
318
  */
319
  public function disablePluginManipulation( $aAllCaps, $cap, $aArgs ) {
320
- // If we're registered with Admin Access we can do everything!
321
- if ( $this->isSecurityAdmin() ) {
322
- return $aAllCaps;
323
- }
324
 
325
  /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
326
  $oFO = $this->getMod();
@@ -449,10 +541,6 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends ICWP_WPSF_Processor_Bas
449
  /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
450
  $oFO = $this->getMod();
451
 
452
- if ( $oFO->doCheckHasPermissionToSubmit() ) {
453
- return;
454
- }
455
-
456
  $aRenderData = array(
457
  'strings' => array(
458
  'editing_restricted' => _wpsf__( 'Editing this option is currently restricted.' ),
16
  public function run() {
17
  /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
18
  $oFO = $this->getMod();
 
19
 
20
  add_filter( $oFO->prefix( 'has_permission_to_manage' ), array( $oFO, 'doCheckHasPermissionToSubmit' ) );
21
  add_filter( $oFO->prefix( 'has_permission_to_view' ), array( $oFO, 'doCheckHasPermissionToSubmit' ) );
22
 
23
+ if ( !$oFO->isUpgrading() && !$this->loadWp()->isRequestUserLogin() ) {
24
  add_filter( 'pre_update_option', array( $this, 'blockOptionsSaves' ), 1, 3 );
25
  }
26
 
27
+ // Setup all the sec admin hooks
28
+ add_action( 'init', array( $this, 'onWpInit' ) );
29
+
30
+ if ( $oFO->isWlEnabled() ) {
31
+ $this->runWhiteLabel();
32
+ }
33
+ }
34
+
35
+ public function onWpInit() {
36
+ /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
37
+ $oFO = $this->getMod();
38
+ if ( !$this->loadWpUsers()->isUserLoggedIn() || $this->isSecurityAdmin() ) {
39
+ return;
40
+ }
41
+
42
+ if ( $oFO->isAdminAccessAdminUsersEnabled() ) {
43
+ add_filter( 'editable_roles', array( $this, 'restrictEditableRoles' ), 100, 1 );
44
+ add_filter( 'user_has_cap', array( $this, 'restrictAdminUserChanges' ), 100, 3 );
45
+ add_action( 'delete_user', array( $this, 'restrictAdminUserDelete' ), 100, 1 );
46
+ add_action( 'add_user_role', array( $this, 'restrictAddUserRole' ), 100, 2 );
47
+ add_action( 'remove_user_role', array( $this, 'restrictRemoveUserRole' ), 100, 2 );
48
+ add_action( 'set_user_role', array( $this, 'restrictSetUserRole' ), 100, 3 );
49
  }
50
 
51
  $aPluginRestrictions = $oFO->getAdminAccessArea_Plugins();
66
  if ( !$this->getController()->isThisPluginModuleRequest() ) {
67
  add_action( 'admin_footer', array( $this, 'printAdminAccessAjaxForm' ) );
68
  }
 
 
 
 
69
  }
70
 
71
  /**
116
  return self::getController()->getHasPermissionToManage();
117
  }
118
 
119
+ /**
120
+ * @param int $nUserId
121
+ * @param string $sRole
122
+ */
123
+ public function restrictAddUserRole( $nUserId, $sRole ) {
124
+ $oWpUsers = $this->loadWpUsers();
125
+
126
+ if ( $oWpUsers->getCurrentWpUserId() !== $nUserId && strtolower( $sRole ) === 'administrator' ) {
127
+ $oModUser = $oWpUsers->getUserById( $nUserId );
128
+ remove_action( 'remove_user_role', array( $this, 'restrictRemoveUserRole' ), 100 );
129
+ $oModUser->remove_role( 'administrator' );
130
+ add_action( 'remove_user_role', array( $this, 'restrictRemoveUserRole' ), 100, 2 );
131
+ }
132
+ }
133
+
134
+ /**
135
+ * @param int $nUserId
136
+ * @param string $sRole
137
+ * @param array $aOldRoles
138
+ */
139
+ public function restrictSetUserRole( $nUserId, $sRole, $aOldRoles = array() ) {
140
+ $oWpUsers = $this->loadWpUsers();
141
+
142
+ $sRole = strtolower( $sRole );
143
+ if ( !is_array( $aOldRoles ) ) {
144
+ $aOldRoles = array();
145
+ }
146
+
147
+ if ( $oWpUsers->getCurrentWpUserId() !== $nUserId ) {
148
+ $bNewRoleIsAdmin = $sRole == 'administrator';
149
+
150
+ // 1. Setting administrator role where it doesn't previously exist
151
+ if ( $bNewRoleIsAdmin && !in_array( 'administrator', $aOldRoles ) ) {
152
+ $bRevert = true;
153
+ }
154
+ // 2. Setting non-administrator role when previous roles included administrator
155
+ else if ( !$bNewRoleIsAdmin && in_array( 'administrator', $aOldRoles ) ) {
156
+ $bRevert = true;
157
+ }
158
+ else {
159
+ $bRevert = false;
160
+ }
161
+
162
+ if ( $bRevert ) {
163
+ $oModUser = $oWpUsers->getUserById( $nUserId );
164
+ remove_action( 'add_user_role', array( $this, 'restrictAddUserRole' ), 100 );
165
+ remove_action( 'remove_user_role', array( $this, 'restrictRemoveUserRole' ), 100 );
166
+ $oModUser->remove_role( $sRole );
167
+ foreach ( $aOldRoles as $sPreExistingRoles ) {
168
+ $oModUser->add_role( $sPreExistingRoles );
169
+ }
170
+ add_action( 'add_user_role', array( $this, 'restrictAddUserRole' ), 100, 2 );
171
+ add_action( 'remove_user_role', array( $this, 'restrictRemoveUserRole' ), 100, 2 );
172
+ }
173
+ }
174
+ }
175
+
176
+ /**
177
+ * @param int $nUserId
178
+ * @param string $sRole
179
+ */
180
+ public function restrictRemoveUserRole( $nUserId, $sRole ) {
181
+ $oWpUsers = $this->loadWpUsers();
182
+
183
+ if ( $oWpUsers->getCurrentWpUserId() !== $nUserId && strtolower( $sRole ) === 'administrator' ) {
184
+ $oModUser = $oWpUsers->getUserById( $nUserId );
185
+ remove_action( 'add_user_role', array( $this, 'restrictAddUserRole' ), 100 );
186
+ $oModUser->add_role( 'administrator' );
187
+ add_action( 'add_user_role', array( $this, 'restrictAddUserRole' ), 100, 2 );
188
+ }
189
+ }
190
+
191
  /**
192
  * @param int $nId
193
  */
194
  public function restrictAdminUserDelete( $nId ) {
195
+ $oWpUsers = $this->loadWpUsers();
196
+ $oUserToDelete = $oWpUsers->getUserById( $nId );
197
+ if ( $oUserToDelete && $oWpUsers->isUserAdmin( $oUserToDelete ) ) {
198
+ $this->loadWp()
199
+ ->wpDie( 'Sorry, deleting administrators is currently restricted to your Security Admin' );
 
 
200
  }
201
  }
202
 
203
  /**
204
+ * @param array[] $aAllRoles
205
+ * @return array[]
206
+ */
207
+ public function restrictEditableRoles( $aAllRoles ) {
208
+ if ( isset( $aAllRoles[ 'administrator' ] ) ) {
209
+ unset( $aAllRoles[ 'administrator' ] );
210
+ }
211
+ return $aAllRoles;
212
+ }
213
+
214
+ /**
215
+ * This hooked function captures the attempts to modify the user role using the standard
216
+ * WordPress profile edit pages. It doesn't sufficiently capture the AJAX request to
217
+ * modify user roles. (see user role hooks)
218
  * @param array $aAllCaps
219
  * @param $cap
220
  * @param array $aArgs
221
  * @return array
222
  */
223
  public function restrictAdminUserChanges( $aAllCaps, $cap, $aArgs ) {
224
+ /** @var string $sUserCap */
225
+ $sUserCap = $aArgs[ 0 ];
 
 
226
 
227
+ $aReleventCaps = array( 'edit_users', 'create_users' );
 
228
 
229
+ // If we're registered with Admin Access we don't modify anything
230
+ if ( in_array( $sUserCap, $aReleventCaps ) ) {
231
+ $bBlockCapability = false;
 
 
232
 
233
+ $oDp = $this->loadDP();
234
+ $oWpUsers = $this->loadWpUsers();
235
 
236
  // Find the WP_User for the POST
237
  $oPostUser = false;
246
  $oPostUser = $oWpUsers->getUserByUsername( $sPostUserlogin );
247
  }
248
 
249
+ $sRequestRole = strtolower( $oDp->post( 'role', '' ) );
250
 
251
  if ( $oPostUser instanceof WP_User ) {
252
  // editing an existing user other than yourself?
253
+ if ( $oPostUser->user_login != $oWpUsers->getCurrentWpUsername() ) {
254
 
255
  if ( $oWpUsers->isUserAdmin( $oPostUser ) || ( $sRequestRole == 'administrator' ) ) {
256
  $bBlockCapability = true;
257
  }
258
  }
259
  }
260
+ else {//creating a new admin user?
 
261
  if ( $sRequestRole == 'administrator' ) {
262
  $bBlockCapability = true;
263
  }
264
  }
 
265
 
266
+ if ( $bBlockCapability ) {
267
+ $aAllCaps[ $sUserCap ] = false;
268
+ }
269
  }
270
 
271
  return $aAllCaps;
273
 
274
  /**
275
  * @param array $aNoticeAttributes
276
+ * @throws Exception
277
  */
278
  public function addNotice_certain_options_restricted( $aNoticeAttributes ) {
279
  /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
311
 
312
  /**
313
  * @param array $aNoticeAttributes
314
+ * @throws Exception
315
  */
316
  public function addNotice_admin_users_restricted( $aNoticeAttributes ) {
317
+ if ( $this->isSecurityAdmin() ) {
 
 
318
  return;
319
  }
320
 
321
+ /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
322
+ $oFO = $this->getMod();
323
+
324
  $sCurrentPage = $this->loadWp()->getCurrentPage();
325
  if ( !in_array( $sCurrentPage, $this->getUserPagesToRestrict() ) ) {
326
  return;
413
  * @return array
414
  */
415
  public function disablePluginManipulation( $aAllCaps, $cap, $aArgs ) {
 
 
 
 
416
 
417
  /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
418
  $oFO = $this->getMod();
541
  /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oFO */
542
  $oFO = $this->getMod();
543
 
 
 
 
 
544
  $aRenderData = array(
545
  'strings' => array(
546
  'editing_restricted' => _wpsf__( 'Editing this option is currently restricted.' ),
src/processors/adminaccess_whitelabel.php CHANGED
@@ -107,7 +107,7 @@ class ICWP_WPSF_Processor_AdminAccess_Whitelabel extends ICWP_WPSF_Processor_Bas
107
  $aPluginLabels[ 'icon_url_128x128' ] = $sLogoUrl;
108
  }
109
 
110
- return $aPluginLabels;
111
  }
112
 
113
  /**
107
  $aPluginLabels[ 'icon_url_128x128' ] = $sLogoUrl;
108
  }
109
 
110
+ return array_merge( $aWhiteLabels, $aPluginLabels );
111
  }
112
 
113
  /**
src/processors/autoupdates.php CHANGED
@@ -270,21 +270,10 @@ class ICWP_WPSF_Processor_Autoupdates extends ICWP_WPSF_Processor_BaseWpsf {
270
  // first, is global auto updates for plugins set
271
  if ( $oFO->isAutoupdateAllPlugins() ) {
272
  $this->doStatIncrement( 'autoupdates.plugins.all' );
273
- return true;
274
- }
275
-
276
- // If it's this plugin and autoupdate this plugin is set...
277
- if ( $sFile === $oFO->getConn()->getPluginBaseFile() ) {
278
  $bDoAutoUpdate = true;
279
- if ( $this->loadWp()->isRunningAutomaticUpdates() ) {
280
- $this->doStatIncrement( 'autoupdates.plugins.self' );
281
- }
282
  }
283
- else {
284
- $aAutoUpdates = $oFO->getAutoupdatePlugins();
285
- if ( !empty( $aAutoUpdates ) && is_array( $aAutoUpdates ) && in_array( $sFile, $aAutoUpdates ) ) {
286
- $bDoAutoUpdate = true;
287
- }
288
  }
289
 
290
  return $bDoAutoUpdate;
270
  // first, is global auto updates for plugins set
271
  if ( $oFO->isAutoupdateAllPlugins() ) {
272
  $this->doStatIncrement( 'autoupdates.plugins.all' );
 
 
 
 
 
273
  $bDoAutoUpdate = true;
 
 
 
274
  }
275
+ else if ( $oFO->isPluginSetToAutoupdate( $sFile ) ) {
276
+ $bDoAutoUpdate = true;
 
 
 
277
  }
278
 
279
  return $bDoAutoUpdate;
src/processors/base.php CHANGED
@@ -192,7 +192,7 @@ abstract class ICWP_WPSF_Processor_Base extends ICWP_WPSF_Foundation {
192
  && !$aNoticeData[ 'notice_attributes' ][ 'can_dismiss' ];
193
 
194
  $oNotices = $this->loadWpNotices();
195
- if ( !$oNotices->isDismissed( $aAttrs[ 'id' ] ) || $bCantDismiss ) {
196
 
197
  $sRenderedNotice = $this->getMod()->renderAdminNotice( $aNoticeData );
198
  if ( !empty( $sRenderedNotice ) ) {
192
  && !$aNoticeData[ 'notice_attributes' ][ 'can_dismiss' ];
193
 
194
  $oNotices = $this->loadWpNotices();
195
+ if ( $bCantDismiss || !$oNotices->isDismissed( $aAttrs[ 'id' ] ) ) {
196
 
197
  $sRenderedNotice = $this->getMod()->renderAdminNotice( $aNoticeData );
198
  if ( !empty( $sRenderedNotice ) ) {
src/processors/base_wpsf.php CHANGED
@@ -135,15 +135,6 @@ abstract class ICWP_WPSF_Processor_BaseWpsf extends ICWP_WPSF_Processor_Base {
135
  return $this;
136
  }
137
 
138
- /**
139
- * Used to mark an IP address for transgression/black-mark
140
- * @return $this
141
- */
142
- public function setIpTransgressed() {
143
- add_filter( $this->getMod()->prefix( 'ip_black_mark' ), '__return_true' );
144
- return $this;
145
- }
146
-
147
  /**
148
  * @return bool
149
  */
@@ -179,20 +170,12 @@ abstract class ICWP_WPSF_Processor_BaseWpsf extends ICWP_WPSF_Processor_Base {
179
  }
180
 
181
  /**
182
- * Filter used to collect plugin data for tracking. Fired from the plugin processor only if the option is enabled
183
- * - it is not enabled by default.
184
- * Note that in this case we "mask" options that have been identified as "sensitive" - i.e. could contain
185
- * identifiable data.
186
- * @param $aData
187
- * @return array
188
  */
189
- public function tracking_DataCollect( $aData ) {
190
- if ( !is_array( $aData ) ) {
191
- $aData = array();
192
- }
193
- $oFO = $this->getMod();
194
- $aData[ $oFO->getSlug() ] = array( 'options' => $oFO->collectOptionsForTracking() );
195
- return $aData;
196
  }
197
 
198
  /**
@@ -235,6 +218,23 @@ abstract class ICWP_WPSF_Processor_BaseWpsf extends ICWP_WPSF_Processor_Base {
235
  return $this->aStatistics;
236
  }
237
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  /**
239
  * This is the preferred method over $this->stat_Increment() since it handles the parent stat key
240
  * @param string $sStatKey
135
  return $this;
136
  }
137
 
 
 
 
 
 
 
 
 
 
138
  /**
139
  * @return bool
140
  */
170
  }
171
 
172
  /**
173
+ * Used to mark an IP address for transgression/black-mark
174
+ * @return $this
 
 
 
 
175
  */
176
+ public function setIpTransgressed() {
177
+ add_filter( $this->getMod()->prefix( 'ip_black_mark' ), '__return_true' );
178
+ return $this;
 
 
 
 
179
  }
180
 
181
  /**
218
  return $this->aStatistics;
219
  }
220
 
221
+ /**
222
+ * Filter used to collect plugin data for tracking. Fired from the plugin processor only if the option is enabled
223
+ * - it is not enabled by default.
224
+ * Note that in this case we "mask" options that have been identified as "sensitive" - i.e. could contain
225
+ * identifiable data.
226
+ * @param $aData
227
+ * @return array
228
+ */
229
+ public function tracking_DataCollect( $aData ) {
230
+ if ( !is_array( $aData ) ) {
231
+ $aData = array();
232
+ }
233
+ $oFO = $this->getMod();
234
+ $aData[ $oFO->getSlug() ] = array( 'options' => $oFO->collectOptionsForTracking() );
235
+ return $aData;
236
+ }
237
+
238
  /**
239
  * This is the preferred method over $this->stat_Increment() since it handles the parent stat key
240
  * @param string $sStatKey
src/processors/basedb.php CHANGED
@@ -19,6 +19,11 @@ abstract class ICWP_WPSF_BaseDbProcessor extends ICWP_WPSF_Processor_BaseWpsf {
19
  */
20
  protected $bTableExists;
21
 
 
 
 
 
 
22
  /**
23
  * @var integer
24
  */
@@ -40,7 +45,7 @@ abstract class ICWP_WPSF_BaseDbProcessor extends ICWP_WPSF_Processor_BaseWpsf {
40
  * @return bool
41
  */
42
  public function isReadyToRun() {
43
- return ( parent::isReadyToRun() && $this->getTableExists() );
44
  }
45
 
46
  /**
@@ -58,17 +63,22 @@ abstract class ICWP_WPSF_BaseDbProcessor extends ICWP_WPSF_Processor_BaseWpsf {
58
  protected function createTable() {
59
  $sSql = $this->getCreateTableSql();
60
  if ( !empty( $sSql ) ) {
 
61
  return $this->loadDbProcessor()->dbDelta( $sSql );
62
  }
63
  return true;
64
  }
65
 
66
  /**
 
67
  */
68
  protected function initializeTable() {
69
  if ( $this->getTableExists() ) {
70
- if ( !$this->tableIsValid() ) {
71
- $this->recreateTable();
 
 
 
72
  }
73
  $sFullHookName = $this->getDbCleanupHookName();
74
  add_action( $sFullHookName, array( $this, 'cleanupDatabase' ) );
@@ -76,6 +86,7 @@ abstract class ICWP_WPSF_BaseDbProcessor extends ICWP_WPSF_Processor_BaseWpsf {
76
  else {
77
  $this->createTable();
78
  }
 
79
  }
80
 
81
  /**
@@ -168,7 +179,7 @@ abstract class ICWP_WPSF_BaseDbProcessor extends ICWP_WPSF_Processor_BaseWpsf {
168
  /**
169
  * @return bool
170
  */
171
- protected function tableIsValid() {
172
  $aColumnsByDefinition = array_map( 'strtolower', $this->getTableColumnsByDefinition() );
173
  $aActualColumns = $this->loadDbProcessor()->getColumnsForTable( $this->getTableName(), 'strtolower' );
174
  $bValid = ( count( array_diff( $aActualColumns, $aColumnsByDefinition ) ) <= 0
@@ -293,6 +304,25 @@ abstract class ICWP_WPSF_BaseDbProcessor extends ICWP_WPSF_Processor_BaseWpsf {
293
  return null;
294
  }
295
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  /**
297
  * @return string
298
  */
19
  */
20
  protected $bTableExists;
21
 
22
+ /**
23
+ * @var bool
24
+ */
25
+ protected $bTableStructureIsValid;
26
+
27
  /**
28
  * @var integer
29
  */
45
  * @return bool
46
  */
47
  public function isReadyToRun() {
48
+ return ( parent::isReadyToRun() && $this->getTableExists() && $this->isTableStructureValid() );
49
  }
50
 
51
  /**
63
  protected function createTable() {
64
  $sSql = $this->getCreateTableSql();
65
  if ( !empty( $sSql ) ) {
66
+ $this->clearTableIsValid();
67
  return $this->loadDbProcessor()->dbDelta( $sSql );
68
  }
69
  return true;
70
  }
71
 
72
  /**
73
+ * @return $this
74
  */
75
  protected function initializeTable() {
76
  if ( $this->getTableExists() ) {
77
+ if ( !$this->isTableStructureValid() ) {
78
+ $this->createTable(); // First attempt the delta
79
+ if ( !$this->isTableStructureValid( true ) ) {
80
+ $this->recreateTable();
81
+ }
82
  }
83
  $sFullHookName = $this->getDbCleanupHookName();
84
  add_action( $sFullHookName, array( $this, 'cleanupDatabase' ) );
86
  else {
87
  $this->createTable();
88
  }
89
+ return $this;
90
  }
91
 
92
  /**
179
  /**
180
  * @return bool
181
  */
182
+ protected function testTableStructure() {
183
  $aColumnsByDefinition = array_map( 'strtolower', $this->getTableColumnsByDefinition() );
184
  $aActualColumns = $this->loadDbProcessor()->getColumnsForTable( $this->getTableName(), 'strtolower' );
185
  $bValid = ( count( array_diff( $aActualColumns, $aColumnsByDefinition ) ) <= 0
304
  return null;
305
  }
306
 
307
+ /**
308
+ * @return $this
309
+ */
310
+ protected function clearTableIsValid() {
311
+ unset( $this->bTableStructureIsValid );
312
+ return $this;
313
+ }
314
+
315
+ /**
316
+ * @param bool $bRetest
317
+ * @return bool
318
+ */
319
+ protected function isTableStructureValid( $bRetest = false ) {
320
+ if ( $bRetest || !isset( $this->bTableStructureIsValid ) ) {
321
+ $this->bTableStructureIsValid = $this->testTableStructure();
322
+ }
323
+ return $this->bTableStructureIsValid;
324
+ }
325
+
326
  /**
327
  * @return string
328
  */
src/processors/comments_filter.php CHANGED
@@ -72,7 +72,7 @@ class ICWP_WPSF_Processor_CommentsFilter extends ICWP_WPSF_Processor_BaseWpsf {
72
  'click_to_deactivate' => _wpsf__( 'Click to deactivate Akismet now.' ),
73
  ),
74
  'hrefs' => array(
75
- 'deactivate' => $oWpPlugins->getLinkPluginDeactivate( $sPluginFile )
76
  )
77
  );
78
  $this->insertAdminNotice( $aRenderData );
72
  'click_to_deactivate' => _wpsf__( 'Click to deactivate Akismet now.' ),
73
  ),
74
  'hrefs' => array(
75
+ 'deactivate' => $oWpPlugins->getUrl_Deactivate( $sPluginFile )
76
  )
77
  );
78
  $this->insertAdminNotice( $aRenderData );
src/processors/email.php CHANGED
@@ -93,7 +93,7 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
93
  public function sendEmailWithWrap( $sAddress = '', $sSubject = '', $aMessage = array() ) {
94
  return $this->send(
95
  $sAddress,
96
- $sSubject,
97
  '<html>'.implode( "<br />", array_merge( $this->getEmailHeader(), $aMessage, $this->getEmailFooter() ) ).'</html>'
98
  );
99
  }
@@ -114,7 +114,7 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
114
  $this->emailFilters( true );
115
  $bSuccess = wp_mail(
116
  $this->verifyEmailAddress( $sAddress ),
117
- wp_specialchars_decode( sprintf( '[%s] %s', $this->loadWp()->getSiteName(), $sSubject ) ),
118
  $sMessageBody
119
  );
120
  $this->emailFilters( false );
93
  public function sendEmailWithWrap( $sAddress = '', $sSubject = '', $aMessage = array() ) {
94
  return $this->send(
95
  $sAddress,
96
+ wp_specialchars_decode( sprintf( '[%s] %s', $this->loadWp()->getSiteName(), $sSubject ) ),
97
  '<html>'.implode( "<br />", array_merge( $this->getEmailHeader(), $aMessage, $this->getEmailFooter() ) ).'</html>'
98
  );
99
  }
114
  $this->emailFilters( true );
115
  $bSuccess = wp_mail(
116
  $this->verifyEmailAddress( $sAddress ),
117
+ $sSubject,
118
  $sMessageBody
119
  );
120
  $this->emailFilters( false );
src/processors/firewall.php CHANGED
@@ -8,7 +8,7 @@ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
10
 
11
- protected $aWhitelistPages;
12
 
13
  /**
14
  * @var array
@@ -364,10 +364,18 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
364
  $aRequestUriParts = $oDp->getRequestUriParts();
365
  $sRequestPage = $aRequestUriParts[ 'path' ];
366
 
367
- // first we remove globally whitelist request parameters
368
- if ( array_key_exists( '*', $aWhitelistPages ) ) {
369
  foreach ( $aWhitelistPages[ '*' ] as $sWhitelistParam ) {
370
- if ( array_key_exists( $sWhitelistParam, $this->aPageParams ) ) {
 
 
 
 
 
 
 
 
371
  unset( $this->aPageParams[ $sWhitelistParam ] );
372
  }
373
  }
@@ -414,45 +422,13 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
414
  * @return array
415
  */
416
  protected function getWhitelistPages() {
417
- if ( !isset( $this->aWhitelistPages ) ) {
418
-
419
- $aDefaultWlPages = array(
420
- '/wp-admin/options-general.php' => array(),
421
- '/wp-admin/post-new.php' => array(),
422
- '/wp-admin/page-new.php' => array(),
423
- '/wp-admin/link-add.php' => array(),
424
- '/wp-admin/media-upload.php' => array(),
425
- '/wp-admin/post.php' => array( 'content' ),
426
- '/wp-admin/plugin-editor.php' => array( 'newcontent' ),
427
- '/wp-admin/page.php' => array(),
428
- '/wp-admin/admin-ajax.php' => array(),
429
- '/wp-comments-post.php' => array(
430
- 'url',
431
- 'comment'
432
- ),
433
- '*' => array(
434
- 'g-recaptcha-response',
435
- 'verify_sign',
436
- 'txn_id',
437
- 'wp_http_referer',
438
- '_wp_http_referer',
439
- '_wp_original_http_referer',
440
- 'pwd',
441
- 'url',
442
- 'referredby',
443
- 'redirect_to',
444
- 'jetpack_sso_original_request',
445
- 'jetpack_sso_redirect_to'
446
- )
447
- );
448
-
449
  /** @var ICWP_WPSF_FeatureHandler_Firewall $oFO */
450
  $oFO = $this->getMod();
451
- $aCustomWhitelistPageParams = $oFO->getPageParamWhitelist();
452
- $this->aWhitelistPages = array_merge_recursive( $aDefaultWlPages, $aCustomWhitelistPageParams );
453
  }
454
-
455
- return $this->aWhitelistPages;
456
  }
457
 
458
  /**
8
 
9
  class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
10
 
11
+ protected $aWhitelist;
12
 
13
  /**
14
  * @var array
364
  $aRequestUriParts = $oDp->getRequestUriParts();
365
  $sRequestPage = $aRequestUriParts[ 'path' ];
366
 
367
+ // first we remove globally whitelisted request parameters
368
+ if ( !empty( $aWhitelistPages[ '*' ] ) && is_array( $aWhitelistPages[ '*' ] ) ) {
369
  foreach ( $aWhitelistPages[ '*' ] as $sWhitelistParam ) {
370
+
371
+ if ( preg_match( '#^/.+/$#', $sWhitelistParam ) ) {
372
+ foreach ( array_keys( $this->aPageParams ) as $sParamKey ) {
373
+ if ( preg_match( $sWhitelistParam, $sParamKey ) ) {
374
+ unset( $this->aPageParams[ $sParamKey ] );
375
+ }
376
+ }
377
+ }
378
+ else if ( isset( $this->aPageParams[ $sWhitelistParam ] ) ) {
379
  unset( $this->aPageParams[ $sWhitelistParam ] );
380
  }
381
  }
422
  * @return array
423
  */
424
  protected function getWhitelistPages() {
425
+ if ( !isset( $this->aWhitelist ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
426
  /** @var ICWP_WPSF_FeatureHandler_Firewall $oFO */
427
  $oFO = $this->getMod();
428
+ $this->aWhitelist = $this->loadDP()
429
+ ->mergeArraysRecursive( $oFO->getDefaultWhitelist(), $oFO->getCustomWhitelist() );
430
  }
431
+ return $this->aWhitelist;
 
432
  }
433
 
434
  /**
src/processors/hackprotect_ptguard.php CHANGED
@@ -57,7 +57,6 @@ class ICWP_WPSF_Processor_HackProtect_PTGuard extends ICWP_WPSF_Processor_CronBa
57
  }
58
 
59
  public function printPluginReinstallDialogs() {
60
-
61
  $aRenderData = array(
62
  'strings' => array(
63
  'editing_restricted' => _wpsf__( 'Editing this option is currently restricted.' ),
57
  }
58
 
59
  public function printPluginReinstallDialogs() {
 
60
  $aRenderData = array(
61
  'strings' => array(
62
  'editing_restricted' => _wpsf__( 'Editing this option is currently restricted.' ),
src/processors/ips.php CHANGED
@@ -36,8 +36,6 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
36
 
37
  /** @var ICWP_WPSF_FeatureHandler_Ips $oFO */
38
  $oFO = $this->getMod();
39
- add_filter( $oFO->prefix( 'visitor_is_whitelisted' ), array( $this, 'fGetIsVisitorWhitelisted' ), 1000 );
40
-
41
  if ( $oFO->isAutoBlackListFeatureEnabled() ) {
42
  add_filter( $oFO->prefix( 'firewall_die_message' ), array( $this, 'fAugmentFirewallDieMessage' ) );
43
  add_action( $oFO->prefix( 'pre_plugin_shutdown' ), array( $this, 'action_blackMarkIp' ) );
@@ -45,14 +43,14 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
45
  }
46
 
47
  add_filter( 'authenticate', array( $this, 'addLoginFailedWarningMessage' ), 10000, 1 );
48
- add_filter( $oFO->prefix( 'has_permission_to_manage' ), array( $this, 'fGetIsVisitorWhitelisted' ) );
49
  add_action( 'template_redirect', array( $this, 'doTrack404' ) );
50
  }
51
 
52
  public function doTrack404() {
53
  /** @var ICWP_WPSF_FeatureHandler_Ips $oFO */
54
  $oFO = $this->getMod();
55
- if ( $oFO->is404Tracking() && is_404() ) {
56
  if ( $oFO->getOptTracking404() == 'assign-transgression' ) {
57
  $this->setIpTransgressed(); // We now black mark this IP
58
  }
@@ -81,9 +79,9 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
81
  * @param array $aNoticeAttributes
82
  */
83
  public function addNotice_visitor_whitelisted( $aNoticeAttributes ) {
 
84
 
85
- if ( $this->getController()->getIsPage_PluginAdmin() && $this->isVisitorWhitelisted() ) {#
86
- $oCon = $this->getController();
87
  $aRenderData = array(
88
  'notice_attributes' => $aNoticeAttributes,
89
  'strings' => array(
@@ -136,7 +134,7 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
136
  */
137
  public function verifyIfAuthenticationValid( $oUserOrError, $sUsername ) {
138
  // Don't concern yourself if visitor is whitelisted
139
- if ( $this->isVisitorWhitelisted() ) {
140
  return $oUserOrError;
141
  }
142
 
@@ -205,9 +203,7 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
205
  }
206
 
207
  protected function processBlacklist() {
208
-
209
- // white list rules
210
- if ( $this->isVisitorWhitelisted() ) {
211
  return;
212
  }
213
 
@@ -245,13 +241,6 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
245
  }
246
  }
247
 
248
- /**
249
- * @return boolean
250
- */
251
- protected function isVisitorWhitelisted() {
252
- return apply_filters( $this->getMod()->prefix( 'visitor_is_whitelisted' ), false );
253
- }
254
-
255
  /**
256
  */
257
  public function action_blackMarkIp() {
@@ -264,15 +253,15 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
264
  /** @var ICWP_WPSF_FeatureHandler_Ips $oFO */
265
  $oFO = $this->getMod();
266
 
267
- if ( $this->getIfIpTransgressed() ) {
268
 
269
  // Never black mark IPs that are on the whitelist
270
  $oIP = $this->loadIpService();
271
  $bCanBlackMark = !$oFO->isPluginDeleting() && $oFO->isAutoBlackListFeatureEnabled()
272
- && !$this->isVisitorWhitelisted() && ( $oIP->whatIsMyIp() !== $this->ip() );
273
 
274
  if ( $bCanBlackMark ) {
275
- $this->blackMarkIp( $this->ip() );
276
  }
277
  }
278
  }
@@ -280,7 +269,7 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
280
  /**
281
  * @param string $sIp
282
  */
283
- protected function blackMarkIp( $sIp ) {
284
  /** @var ICWP_WPSF_FeatureHandler_Ips $oFO */
285
  $oFO = $this->getMod();
286
  $oFO->setOptInsightsAt( 'last_transgression_at' );
@@ -307,27 +296,22 @@ class ICWP_WPSF_Processor_Ips extends ICWP_WPSF_BaseDbProcessor {
307
  }
308
 
309
  /**
310
- * @param boolean $bIsWhitelisted
311
- * @return boolean
312
  */
313
- public function fGetIsVisitorWhitelisted( $bIsWhitelisted ) {
314
  if ( !isset( $this->bVisitorIsWhitelisted ) ) {
315
- $this->bVisitorIsWhitelisted = $this->getIsIpOnWhiteList( $this->ip() );
316
  }
317
- return ( $bIsWhitelisted || $this->bVisitorIsWhitelisted ); //so we still support the legacy lists
318
  }
319
 
320
  /**
321
  * @param string $sIp
322
- * @param bool $bReturnListData
323
- * @return bool|array
324
  */
325
- public function getIsIpOnWhiteList( $sIp, $bReturnListData = false ) {
326
-
327
  $aIpData = $this->getIpListData( $sIp, array( ICWP_WPSF_FeatureHandler_Ips::LIST_MANUAL_WHITE ) );
328
- $bOnList = count( $aIpData ) > 0;
329
-
330
- return ( $bOnList && $bReturnListData ) ? $aIpData : $bOnList;
331
  }
332
 
333
  /**
36
 
37
  /** @var ICWP_WPSF_FeatureHandler_Ips $oFO */
38
  $oFO = $this->getMod();
 
 
39
  if ( $oFO->isAutoBlackListFeatureEnabled() ) {
40
  add_filter( $oFO->prefix( 'firewall_die_message' ), array( $this, 'fAugmentFirewallDieMessage' ) );
41
  add_action( $oFO->prefix( 'pre_plugin_shutdown' ), array( $this, 'action_blackMarkIp' ) );
43
  }
44
 
45
  add_filter( 'authenticate', array( $this, 'addLoginFailedWarningMessage' ), 10000, 1 );
46
+ // add_filter( $oFO->prefix( 'has_permission_to_manage' ), array( $this, 'isCurrentIpWhitelisted' ), 30, 0 );
47
  add_action( 'template_redirect', array( $this, 'doTrack404' ) );
48
  }
49
 
50
  public function doTrack404() {
51
  /** @var ICWP_WPSF_FeatureHandler_Ips $oFO */
52
  $oFO = $this->getMod();
53
+ if ( $oFO->is404Tracking() && is_404() && !$oFO->isVerifiedBot() ) {
54
  if ( $oFO->getOptTracking404() == 'assign-transgression' ) {
55
  $this->setIpTransgressed(); // We now black mark this IP
56
  }
79
  * @param array $aNoticeAttributes
80
  */
81
  public function addNotice_visitor_whitelisted( $aNoticeAttributes ) {
82
+ $oCon = $this->getController();
83
 
84
+ if ( $oCon->getIsPage_PluginAdmin() && $this->isCurrentIpWhitelisted() ) {
 
85
  $aRenderData = array(
86
  'notice_attributes' => $aNoticeAttributes,
87
  'strings' => array(
134
  */
135
  public function verifyIfAuthenticationValid( $oUserOrError, $sUsername ) {
136
  // Don't concern yourself if visitor is whitelisted
137
+ if ( $this->isCurrentIpWhitelisted() ) {
138
  return $oUserOrError;
139
  }
140
 
203
  }
204
 
205
  protected function processBlacklist() {
206
+ if ( $this->isCurrentIpWhitelisted() ) {
 
 
207
  return;
208
  }
209
 
241
  }
242
  }
243
 
 
 
 
 
 
 
 
244
  /**
245
  */
246
  public function action_blackMarkIp() {
253
  /** @var ICWP_WPSF_FeatureHandler_Ips $oFO */
254
  $oFO = $this->getMod();
255
 
256
+ if ( $this->getIfIpTransgressed() && !$oFO->isVerifiedBot() && !$this->isCurrentIpWhitelisted() ) {
257
 
258
  // Never black mark IPs that are on the whitelist
259
  $oIP = $this->loadIpService();
260
  $bCanBlackMark = !$oFO->isPluginDeleting() && $oFO->isAutoBlackListFeatureEnabled()
261
+ && ( $oIP->whatIsMyIp() !== $this->ip() );
262
 
263
  if ( $bCanBlackMark ) {
264
+ $this->processIpBlackMark( $this->ip() );
265
  }
266
  }
267
  }
269
  /**
270
  * @param string $sIp
271
  */
272
+ private function processIpBlackMark( $sIp ) {
273
  /** @var ICWP_WPSF_FeatureHandler_Ips $oFO */
274
  $oFO = $this->getMod();
275
  $oFO->setOptInsightsAt( 'last_transgression_at' );
296
  }
297
 
298
  /**
299
+ * @return bool
 
300
  */
301
+ public function isCurrentIpWhitelisted() {
302
  if ( !isset( $this->bVisitorIsWhitelisted ) ) {
303
+ $this->bVisitorIsWhitelisted = $this->isIpOnWhiteList( $this->ip() );
304
  }
305
+ return $this->bVisitorIsWhitelisted;
306
  }
307
 
308
  /**
309
  * @param string $sIp
310
+ * @return bool
 
311
  */
312
+ public function isIpOnWhiteList( $sIp ) {
 
313
  $aIpData = $this->getIpListData( $sIp, array( ICWP_WPSF_FeatureHandler_Ips::LIST_MANUAL_WHITE ) );
314
+ return ( count( $aIpData ) > 0 );
 
 
315
  }
316
 
317
  /**
src/processors/login_protect.php CHANGED
@@ -20,7 +20,7 @@ class ICWP_WPSF_Processor_LoginProtect extends ICWP_WPSF_Processor_BaseWpsf {
20
  return;
21
  }
22
 
23
- if ( $oFO->getIsCustomLoginPathEnabled() ) {
24
  $this->getProcessorWpLogin()->run();
25
  }
26
 
20
  return;
21
  }
22
 
23
+ if ( $oFO->isCustomLoginPathEnabled() ) {
24
  $this->getProcessorWpLogin()->run();
25
  }
26
 
src/processors/loginprotect_backupcodes.php ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( class_exists( 'ICWP_WPSF_Processor_LoginProtect_BackupCodes', false ) ) {
4
+ return;
5
+ }
6
+
7
+ require_once( dirname( __FILE__ ).'/loginprotect_intentprovider_base.php' );
8
+
9
+ class ICWP_WPSF_Processor_LoginProtect_BackupCodes extends ICWP_WPSF_Processor_LoginProtect_IntentProviderBase {
10
+
11
+ /**
12
+ * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
13
+ * functions. Otherwise we need to be careful of mixing up users.
14
+ * @param WP_User $oUser
15
+ */
16
+ public function addOptionsToUserProfile( $oUser ) {
17
+ $oCon = $this->getController();
18
+
19
+ $bValidatedProfile = $this->hasValidatedProfile( $oUser );
20
+ $aData = array(
21
+ 'has_mfa' => $this->isUserSubjectToLoginIntent( $oUser ),
22
+ 'has_validated_profile' => $bValidatedProfile,
23
+ 'user_google_authenticator_secret' => $this->getSecret( $oUser ),
24
+ 'is_my_user_profile' => ( $oUser->ID == $this->loadWpUsers()->getCurrentWpUserId() ),
25
+ 'i_am_valid_admin' => $oCon->getHasPermissionToManage(),
26
+ 'user_to_edit_is_admin' => $this->loadWpUsers()->isUserAdmin( $oUser ),
27
+ 'strings' => array(
28
+ 'button_gen_code' => _wpsf__( 'Generate ONE-Time Backup 2FA Login Code' ),
29
+ 'button_del_code' => _wpsf__( 'Delete Login Backup Code' ),
30
+ 'not_available' => _wpsf__( 'Backup login codes are not available if you do not have any other two-factor authentication modes active.' ),
31
+ 'description_code' => _wpsf__( 'Click to generate a backup login code for your two-factor authentication.' ),
32
+ 'description_code_ext1' => sprintf( '%s: %s',
33
+ _wpsf__( 'Important' ),
34
+ _wpsf__( 'This code will be displayed only once and you may use it to verify your login only once.' )
35
+ .' '._wpsf__( 'Store it somewhere safe.' ) ),
36
+ 'description_code_ext2' => _wpsf__( 'Generating a new code will replace your existing code.' ),
37
+ 'description_chart_url' => _wpsf__( 'Use your Google Authenticator app to scan this QR code and enter the one time password below.' ),
38
+ 'description_ga_secret' => _wpsf__( 'If you have a problem with scanning the QR code enter this code manually into the app.' ),
39
+ 'desc_remove' => _wpsf__( 'Check the box to remove Google Authenticator login authentication.' ),
40
+ 'label_check_to_remove' => sprintf( _wpsf__( 'Remove %s' ), _wpsf__( 'Google Authenticator' ) ),
41
+ 'label_enter_code' => _wpsf__( 'Create Backup 2FA Login Code' ),
42
+ 'label_ga_secret' => _wpsf__( 'Manual Code' ),
43
+ 'label_scan_qr_code' => _wpsf__( 'Scan This QR Code' ),
44
+ 'title' => _wpsf__( 'Backup Login Code' ),
45
+ 'cant_add_other_user' => sprintf( _wpsf__( "Sorry, %s may not be added to another user's account." ), 'Backup Codes' ),
46
+ 'cant_remove_admins' => sprintf( _wpsf__( "Sorry, %s may only be removed from another user's account by a Security Administrator." ), _wpsf__( 'Backup Codes' ) ),
47
+ 'provided_by' => sprintf( _wpsf__( 'Provided by %s' ), $oCon->getHumanName() ),
48
+ 'remove_more_info' => sprintf( _wpsf__( 'Understand how to remove Google Authenticator' ) )
49
+ ),
50
+ 'data' => array(
51
+ 'otp_field_name' => $this->getLoginFormParameter()
52
+ )
53
+ );
54
+
55
+ echo $this->getMod()->renderTemplate( 'snippets/user_profile_backupcode.php', $aData );
56
+ }
57
+
58
+ /**
59
+ * @param WP_User $oUser
60
+ */
61
+ public function addOptionsToUserEditProfile( $oUser ) {
62
+ // Allow no actions to be taken on other user profiles
63
+ }
64
+
65
+ /**
66
+ * @param array $aFields
67
+ * @return array
68
+ */
69
+ public function addLoginIntentField( $aFields ) {
70
+ if ( $this->getCurrentUserHasValidatedProfile() ) {
71
+ $aFields[] = array(
72
+ 'name' => $this->getLoginFormParameter(),
73
+ 'type' => 'text',
74
+ 'value' => '',
75
+ 'placeholder' => _wpsf__( 'Please use your Backup Code to login.' ),
76
+ 'text' => _wpsf__( 'Login Backup Code' ),
77
+ 'help_link' => '',
78
+ );
79
+ }
80
+ return $aFields;
81
+ }
82
+
83
+ /**
84
+ * Backup codes shouldn't make a user subject to login intent, but only be presented as required
85
+ * - i.e. they have other MFA options but they can't be used at the moment. So no MFA options =
86
+ * no need for backup codes
87
+ * @param bool $bIsSubjectTo
88
+ * @param WP_User $oUser
89
+ * @return bool
90
+ */
91
+ public function filterUserSubjectToIntent( $bIsSubjectTo, $oUser ) {
92
+ return $bIsSubjectTo;
93
+ }
94
+
95
+ /**
96
+ * @param WP_User $oUser
97
+ * @return bool
98
+ */
99
+ protected function hasValidatedProfile( $oUser ) {
100
+ return $this->hasValidSecret( $oUser );
101
+ }
102
+
103
+ /**
104
+ * Backup Code are 1-time only and if you have MFA, then we need to remove all the other tracking factors
105
+ * @param WP_User $oUser
106
+ * @param string $sOtpCode
107
+ * @return bool
108
+ */
109
+ protected function processOtp( $oUser, $sOtpCode ) {
110
+ $bValid = $this->validateBackupCode( $oUser, $sOtpCode );
111
+ if ( $bValid ) {
112
+ $this->deleteSecret( $oUser );
113
+ }
114
+ return $bValid;
115
+ }
116
+
117
+ /**
118
+ * @param WP_User $oUser
119
+ * @param string $sOtpCode
120
+ * @return bool
121
+ */
122
+ private function validateBackupCode( $oUser, $sOtpCode ) {
123
+ return wp_check_password( str_replace( '-', '', $sOtpCode ), $this->getSecret( $oUser ) );
124
+ }
125
+
126
+ /**
127
+ * @param WP_User $oUser
128
+ * @param bool $bIsSuccess
129
+ */
130
+ protected function auditLogin( $oUser, $bIsSuccess ) {
131
+ if ( $bIsSuccess ) {
132
+ $this->addToAuditEntry(
133
+ sprintf( _wpsf__( 'User "%s" verified their identity using %s method.' ),
134
+ $oUser->user_login, _wpsf__( 'Backup Code' )
135
+ ), 2, 'login_protect_bc_verified'
136
+ );
137
+ $this->doStatIncrement( 'login.backupcode.verified' );
138
+ }
139
+ else {
140
+ $this->addToAuditEntry(
141
+ sprintf( _wpsf__( 'User "%s" failed to verify their identity using %s method.' ),
142
+ $oUser->user_login, _wpsf__( 'Backup Code' )
143
+ ), 2, 'login_protect_bc_failed'
144
+ );
145
+ $this->doStatIncrement( 'login.backupcode.fail' );
146
+ }
147
+ }
148
+
149
+ /**
150
+ * @param WP_User $oUser
151
+ * @param bool $bIsOtpSuccess
152
+ * @param bool $bOtpProvided - whether a OTP was actually provided
153
+ * @return $this
154
+ */
155
+ protected function postOtpProcessAction( $oUser, $bIsOtpSuccess, $bOtpProvided ) {
156
+ parent::postOtpProcessAction( $oUser, $bIsOtpSuccess, $bOtpProvided );
157
+
158
+ if ( $bOtpProvided && $bIsOtpSuccess ) {
159
+ $this->sendBackupCodeUsedEmail( $oUser );
160
+ }
161
+ return $this;
162
+ }
163
+
164
+ /**
165
+ * @param WP_User $oUser
166
+ */
167
+ private function sendBackupCodeUsedEmail( $oUser ) {
168
+ $aEmailContent = array(
169
+ _wpsf__( 'This is a quick notice to inform you that your Backup Login code was just used.' ),
170
+ _wpsf__( "Your WordPress account had only 1 backup login code." )
171
+ .' '._wpsf__( "You must go to your profile and regenerate a new code if you want to use this method again." ),
172
+ '',
173
+ sprintf( '<strong>%s</strong>', _wpsf__( 'Login Details' ) ),
174
+ sprintf( '%s: %s', _wpsf__( 'URL' ), $this->loadWp()->getHomeUrl() ),
175
+ sprintf( '%s: %s', _wpsf__( 'Username' ), $oUser->user_login ),
176
+ sprintf( '%s: %s', _wpsf__( 'IP Address' ), $this->ip() ),
177
+ '',
178
+ _wpsf__( 'Thank You.' ),
179
+ );
180
+
181
+ $sTitle = sprintf( _wpsf__( "Notice: %s" ), _wpsf__( "Backup Login Code Just Used" ) );
182
+ $this->getEmailProcessor()
183
+ ->sendEmailWithWrap( $oUser->user_email, $sTitle, $aEmailContent );
184
+ }
185
+
186
+ /**
187
+ * @return string
188
+ */
189
+ protected function genNewSecret() {
190
+ return wp_generate_password( 25, false );
191
+ }
192
+
193
+ /**
194
+ * @param WP_User $oUser
195
+ * @param string $sNewSecret
196
+ * @return $this
197
+ */
198
+ protected function setSecret( $oUser, $sNewSecret ) {
199
+ parent::setSecret( $oUser, wp_hash_password( $sNewSecret ) );
200
+ return $this;
201
+ }
202
+
203
+ /**
204
+ * @return string
205
+ */
206
+ protected function getStub() {
207
+ return ICWP_WPSF_Processor_LoginProtect_Track::Factor_BackupCode;
208
+ }
209
+ }
src/processors/loginprotect_gasp.php CHANGED
@@ -28,7 +28,10 @@ class ICWP_WPSF_Processor_LoginProtect_Gasp extends ICWP_WPSF_Processor_LoginPro
28
  'sAlert' => $this->getTextPleaseCheckBox(),
29
  'sMustJs' => _wpsf__( 'You MUST enable Javascript to be able to login' ),
30
  'sUniqId' => $sUniqId,
31
- 'sUniqElem' => 'icwp_wpsf_login_p'.$sUniqId
 
 
 
32
  )
33
  );
34
  }
28
  'sAlert' => $this->getTextPleaseCheckBox(),
29
  'sMustJs' => _wpsf__( 'You MUST enable Javascript to be able to login' ),
30
  'sUniqId' => $sUniqId,
31
+ 'sUniqElem' => 'icwp_wpsf_login_p'.$sUniqId,
32
+ 'strings' => array(
33
+ 'loading' => _wpsf__( 'Loading' )
34
+ )
35
  )
36
  );
37
  }
src/processors/loginprotect_googleauthenticator.php CHANGED
@@ -192,58 +192,6 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
192
  }
193
  }
194
 
195
- /**
196
- * @param WP_User $oUser
197
- * @return WP_Error|WP_User
198
- */
199
- public function processLoginAttempt_FilterOld( $oUser ) {
200
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
201
- $oFO = $this->getMod();
202
- $oLoginTrack = $this->getLoginTrack();
203
-
204
- // Mulifactor or not
205
- $bNeedToCheckThisFactor = $oFO->isChainedAuth() || !$this->getLoginTrack()->hasSuccessfulFactor();
206
- $bErrorOnFailure = $bNeedToCheckThisFactor && $oLoginTrack->isFinalFactorRemainingToTrack();
207
- $oLoginTrack->addUnSuccessfulFactor( $this->getStub() );
208
-
209
- if ( !$bNeedToCheckThisFactor || !( $oUser instanceof WP_User ) || is_wp_error( $oUser ) ) {
210
- return $oUser;
211
- }
212
-
213
- if ( $this->hasValidatedProfile( $oUser ) ) {
214
-
215
- $oError = new WP_Error();
216
-
217
- $sGaOtp = $this->fetchCodeFromRequest();
218
- $bIsError = false;
219
- if ( empty( $sGaOtp ) ) {
220
- $bIsError = true;
221
- $oError->add( 'shield_google_authenticator_empty',
222
- _wpsf__( 'Whoops.' ).' '._wpsf__( 'Did we forget to use the Google Authenticator?' ) );
223
- }
224
- else {
225
- $sGaOtp = preg_replace( '/[^0-9]/', '', $sGaOtp );
226
- if ( !$this->processOtp( $oUser, $sGaOtp ) ) {
227
- $bIsError = true;
228
- $oError->add( 'shield_google_authenticator_failed',
229
- _wpsf__( 'Oh dear.' ).' '._wpsf__( 'Google Authenticator Code Failed.' ) );
230
- }
231
- }
232
-
233
- if ( $bIsError ) {
234
- if ( $bErrorOnFailure ) {
235
- $oUser = $oError;
236
- }
237
- $this->doStatIncrement( 'login.googleauthenticator.fail' );
238
- }
239
- else {
240
- $this->doStatIncrement( 'login.googleauthenticator.verified' );
241
- $oLoginTrack->addSuccessfulFactor( $this->getStub() );
242
- }
243
- }
244
- return $oUser;
245
- }
246
-
247
  /**
248
  * @param array $aFields
249
  * @return array
@@ -337,17 +285,17 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
337
  protected function auditLogin( $oUser, $bIsSuccess ) {
338
  if ( $bIsSuccess ) {
339
  $this->addToAuditEntry(
340
- sprintf(
341
- _wpsf__( 'User "%s" verified their identity using Google Authenticator Two-Factor Authentication.' ),
342
- $oUser->user_login ), 2, 'login_protect_ga_verified'
343
  );
344
  $this->doStatIncrement( 'login.googleauthenticator.verified' );
345
  }
346
  else {
347
  $this->addToAuditEntry(
348
- sprintf(
349
- _wpsf__( 'User "%s" failed to verify their identity using Google Authenticator Two-Factor Authentication.' ),
350
- $oUser->user_login ), 2, 'login_protect_ga_failed'
351
  );
352
  $this->doStatIncrement( 'login.googleauthenticator.fail' );
353
  }
192
  }
193
  }
194
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  /**
196
  * @param array $aFields
197
  * @return array
285
  protected function auditLogin( $oUser, $bIsSuccess ) {
286
  if ( $bIsSuccess ) {
287
  $this->addToAuditEntry(
288
+ sprintf( _wpsf__( 'User "%s" verified their identity using %s method.' ),
289
+ $oUser->user_login, _wpsf__( 'Google Authenticator' )
290
+ ), 2, 'login_protect_ga_verified'
291
  );
292
  $this->doStatIncrement( 'login.googleauthenticator.verified' );
293
  }
294
  else {
295
  $this->addToAuditEntry(
296
+ sprintf( _wpsf__( 'User "%s" failed to verify their identity using %s method.' ),
297
+ $oUser->user_login, _wpsf__( 'Google Authenticator' )
298
+ ), 2, 'login_protect_ga_failed'
299
  );
300
  $this->doStatIncrement( 'login.googleauthenticator.fail' );
301
  }
src/processors/loginprotect_intent.php CHANGED
@@ -38,13 +38,9 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
38
  * @param int $nUserId
39
  */
40
  public function onWcSocialLogin( $nUserId ) {
41
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
42
- $oFO = $this->getMod();
43
-
44
- $oUser = new WP_User( $nUserId );
45
- if ( $oUser->ID != 0 ) { // i.e. said user id exists.
46
- $oMeta = $this->getController()->getUserMeta( $oUser );
47
- $oMeta->wc_social_login_valid = true;
48
  }
49
  }
50
 
@@ -56,7 +52,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
56
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
57
  $oFO = $this->getMod();
58
 
59
- if ( $oFO->getIsEnabledGoogleAuthenticator() ) {
60
  $this->getProcessorGoogleAuthenticator()->run();
61
  }
62
 
@@ -68,9 +64,14 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
68
  $this->getProcessorYubikey()->run();
69
  }
70
 
 
 
 
 
71
  if ( $this->getLoginTrack()->hasFactorsRemainingToTrack() ) {
72
  if ( $this->loadWp()->isRequestUserLogin() || $oFO->getIfSupport3rdParty() ) {
73
- add_filter( 'authenticate', array( $this, 'initLoginIntent' ), 100, 1 );
 
74
  }
75
 
76
  // process the current login intent
@@ -88,7 +89,44 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
88
  }
89
 
90
  /**
91
- * hooked to 'init' and only run if a user is logged in
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  */
93
  private function processLoginIntent() {
94
  $oWpUsers = $this->loadWpUsers();
@@ -109,13 +147,18 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
109
  }
110
 
111
  if ( $this->isLoginIntentValid() ) {
112
-
113
  if ( $oDp->post( 'skip_mfa' ) === 'Y' ) { // store the browser hash
114
  $oFO->addMfaLoginHash( $oWpUsers->getCurrentWpUser() );
115
  }
116
 
117
  $this->removeLoginIntent();
118
- $oFO->setFlashAdminNotice( _wpsf__( 'Success' ).'! '._wpsf__( 'Thank you for authenticating your login.' ) )
 
 
 
 
 
 
119
  ->setOptInsightsAt( 'last_2fa_login_at' );
120
  }
121
  else {
@@ -138,69 +181,26 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
138
  }
139
  }
140
 
141
- /**
142
- */
143
- public function onWpLogout() {
144
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
145
- $oFO = $this->getMod();
146
-
147
- $this->removeLoginIntent();
148
-
149
- // support for WooCommerce Social Login
150
- if ( $oFO->getIfSupport3rdParty() ) {
151
- $this->getController()->getCurrentUserMeta()->wc_social_login_valid = false;
152
- }
153
- }
154
-
155
- /**
156
- * If it's a valid login attempt (by password) then $oUser is a WP_User
157
- * @param WP_User|WP_Error $oUser
158
- * @return WP_User
159
- */
160
- public function initLoginIntent( $oUser ) {
161
- if ( $oUser instanceof WP_User ) {
162
-
163
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oF */
164
- $oF = $this->getMod();
165
- if ( !$oF->canUserMfaSkip( $oUser ) ) {
166
- $nTimeout = (int)apply_filters(
167
- $oF->prefix( 'login_intent_timeout' ),
168
- $oF->getDef( 'login_intent_timeout' )
169
- );
170
- $this->setLoginIntentExpiresAt( $this->time() + MINUTE_IN_SECONDS*$nTimeout, $oUser );
171
- }
172
- }
173
- return $oUser;
174
- }
175
-
176
  /**
177
  * Use this ONLY when the login intent has been successfully verified.
178
  * @return $this
179
  */
180
  protected function removeLoginIntent() {
181
- unset( $this->getCurrentUserMeta()->login_intent_expires_at );
182
- return $this;
183
- }
184
-
185
- /**
186
- * Reset will put the counter to zero - this should be used when the user HAS NOT
187
- * verified the login intent. To indicate that they have successfully verified, use removeLoginIntent()
188
- * @return $this
189
- */
190
- public function resetLoginIntent() {
191
- $this->setLoginIntentExpiresAt( 0, $this->loadWpUsers()->getCurrentWpUser() );
192
- return $this;
193
  }
194
 
195
  /**
196
- * @param int $nExpirationTime
197
- * @param WP_User $oUser
198
  * @return $this
199
  */
200
- protected function setLoginIntentExpiresAt( $nExpirationTime, $oUser ) {
201
- if ( $oUser instanceof WP_User ) {
202
- $oMeta = $this->loadWpUsers()->metaVoForUser( $this->prefix(), $oUser->ID );
203
- $oMeta->login_intent_expires_at = max( 0, (int)$nExpirationTime );
 
 
 
 
204
  }
205
  return $this;
206
  }
@@ -221,14 +221,17 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
221
  * @return int
222
  */
223
  protected function getLoginIntentExpiresAt() {
224
- return (int)$this->getCurrentUserMeta()->login_intent_expires_at;
 
 
 
225
  }
226
 
227
  /**
228
  * @return bool
229
  */
230
  protected function hasLoginIntent() {
231
- return isset( $this->getCurrentUserMeta()->login_intent_expires_at );
232
  }
233
 
234
  /**
@@ -270,6 +273,8 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
270
 
271
  $sRedirectTo = rawurlencode( $this->loadDP()->getRequestUri() ); // not actually used
272
 
 
 
273
  $nMfaSkip = $oFO->getMfaSkip();
274
  $aDisplayData = array(
275
  'strings' => array(
@@ -301,7 +306,10 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
301
  'shield_logo' => 'https://ps.w.org/wp-simple-firewall/assets/banner-772x250.png',
302
  'redirect_to' => $sRedirectTo,
303
  'what_is_this' => 'https://icontrolwp.freshdesk.com/support/solutions/articles/3000064840',
304
- 'favicon' => $oCon->getPluginUrl_Image( 'pluginlogo_24x24.png' ),
 
 
 
305
  ),
306
  'flags' => array(
307
  'can_skip_mfa' => $oFO->getMfaSkipEnabled(),
@@ -317,6 +325,20 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
317
  return true;
318
  }
319
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  /**
321
  * @return ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth
322
  */
@@ -337,6 +359,15 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
337
  return $oProc->setLoginTrack( $this->getLoginTrack() );
338
  }
339
 
 
 
 
 
 
 
 
 
 
340
  /**
341
  * @return ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator
342
  */
@@ -370,7 +401,21 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
370
  $this->setLoginIntentProcessed();
371
  }
372
  $oTrk = $this->getLoginTrack();
373
- return $oFO->isChainedAuth() ? !$oTrk->hasUnSuccessfulFactor() : $oTrk->hasSuccessfulFactor();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  }
375
 
376
  /**
38
  * @param int $nUserId
39
  */
40
  public function onWcSocialLogin( $nUserId ) {
41
+ $oUser = $this->loadWpUsers()->getUserById( $nUserId );
42
+ if ( $oUser instanceof WP_User ) {
43
+ $this->getController()->getUserMeta( $oUser )->wc_social_login_valid = true;
 
 
 
 
44
  }
45
  }
46
 
52
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
53
  $oFO = $this->getMod();
54
 
55
+ if ( $oFO->isEnabledGoogleAuthenticator() ) {
56
  $this->getProcessorGoogleAuthenticator()->run();
57
  }
58
 
64
  $this->getProcessorYubikey()->run();
65
  }
66
 
67
+ if ( $oFO->isEnabledBackupCodes() ) {
68
+ $this->getProcessorBackupCodes()->run();
69
+ }
70
+
71
  if ( $this->getLoginTrack()->hasFactorsRemainingToTrack() ) {
72
  if ( $this->loadWp()->isRequestUserLogin() || $oFO->getIfSupport3rdParty() ) {
73
+ /** 20180925 - now using set cookie auth instead so we can capture session */
74
+ // add_action( 'authenticate', array( $this, 'initLoginIntent' ), 100, 1 );
75
  }
76
 
77
  // process the current login intent
89
  }
90
 
91
  /**
92
+ * @param string $sUsername
93
+ * @param WP_User $oUser
94
+ */
95
+ public function onWpLogin( $sUsername, $oUser ) {
96
+ $this->initLoginIntent( $oUser );
97
+ }
98
+
99
+ /**
100
+ * @param string $sCookie
101
+ * @param int $nExpire
102
+ * @param int $nExpiration
103
+ * @param int $nUserId
104
+ */
105
+ public function onWpSetLoggedInCookie( $sCookie, $nExpire, $nExpiration, $nUserId ) {
106
+ $this->initLoginIntent( $this->loadWpUsers()->getUserById( $nUserId ) );
107
+ }
108
+
109
+ /**
110
+ * @param WP_User|WP_Error $oUser
111
+ */
112
+ protected function initLoginIntent( $oUser ) {
113
+ if ( !$this->isLoginCaptured() && $oUser instanceof WP_User
114
+ && $this->getLoginTrack()->hasFactorsRemainingToTrack() ) {
115
+
116
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oF */
117
+ $oF = $this->getMod();
118
+ if ( !$oF->canUserMfaSkip( $oUser ) ) {
119
+ $nTimeout = (int)apply_filters(
120
+ $oF->prefix( 'login_intent_timeout' ),
121
+ $oF->getDef( 'login_intent_timeout' )
122
+ );
123
+ $this->setLoginIntentExpiresAt( $this->time() + MINUTE_IN_SECONDS*$nTimeout );
124
+ }
125
+ }
126
+ }
127
+
128
+ /**
129
+ * hooked to 'init' and only run if a user is logged-in (not on the login request)
130
  */
131
  private function processLoginIntent() {
132
  $oWpUsers = $this->loadWpUsers();
147
  }
148
 
149
  if ( $this->isLoginIntentValid() ) {
 
150
  if ( $oDp->post( 'skip_mfa' ) === 'Y' ) { // store the browser hash
151
  $oFO->addMfaLoginHash( $oWpUsers->getCurrentWpUser() );
152
  }
153
 
154
  $this->removeLoginIntent();
155
+ $sFlash = _wpsf__( 'Success' ).'! '._wpsf__( 'Thank you for authenticating your login.' );
156
+ if ( $oFO->isEnabledBackupCodes() ) {
157
+ $sFlash .= ' '._wpsf__( 'If you used your Backup Code, you will need to reset it.' ); //TODO::
158
+ // .' '.sprintf( '<a href="%s">%s</a>', $oWpUsers->getAdminUrl_ProfileEdit(), _wpsf__( 'Go' ) );
159
+ }
160
+
161
+ $oFO->setFlashAdminNotice( $sFlash )
162
  ->setOptInsightsAt( 'last_2fa_login_at' );
163
  }
164
  else {
181
  }
182
  }
183
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  /**
185
  * Use this ONLY when the login intent has been successfully verified.
186
  * @return $this
187
  */
188
  protected function removeLoginIntent() {
189
+ return $this->setLoginIntentExpiresAt( 0 );
 
 
 
 
 
 
 
 
 
 
 
190
  }
191
 
192
  /**
193
+ * @param int $nExpirationTime
 
194
  * @return $this
195
  */
196
+ protected function setLoginIntentExpiresAt( $nExpirationTime ) {
197
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
198
+ $oFO = $this->getMod();
199
+ $oSession = $oFO->getSession();
200
+ if ( $oSession instanceof ICWP_WPSF_SessionVO ) {
201
+ $oFO->getSessionsProcessor()
202
+ ->getQueryUpdater()
203
+ ->updateLoginIntentExpiresAt( $oSession, $nExpirationTime );
204
  }
205
  return $this;
206
  }
221
  * @return int
222
  */
223
  protected function getLoginIntentExpiresAt() {
224
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
225
+ $oFO = $this->getMod();
226
+ $oSess = $oFO->getSession();
227
+ return ( $oSess instanceof ICWP_WPSF_SessionVO ) ? $oSess->getLoginIntentExpiresAt() : 0;
228
  }
229
 
230
  /**
231
  * @return bool
232
  */
233
  protected function hasLoginIntent() {
234
+ return $this->getLoginIntentExpiresAt() > 0;
235
  }
236
 
237
  /**
273
 
274
  $sRedirectTo = rawurlencode( $this->loadDP()->getRequestUri() ); // not actually used
275
 
276
+ $aLabels = $oCon->getPluginLabels();
277
+ $sBannerUrl = empty( $aLabels[ 'url_login2fa_logourl' ] ) ? $oCon->getPluginUrl_Image( 'pluginlogo_banner-772x250.png' ) : $aLabels[ 'url_login2fa_logourl' ];
278
  $nMfaSkip = $oFO->getMfaSkip();
279
  $aDisplayData = array(
280
  'strings' => array(
306
  'shield_logo' => 'https://ps.w.org/wp-simple-firewall/assets/banner-772x250.png',
307
  'redirect_to' => $sRedirectTo,
308
  'what_is_this' => 'https://icontrolwp.freshdesk.com/support/solutions/articles/3000064840',
309
+ ),
310
+ 'imgs' => array(
311
+ 'banner' => $sBannerUrl,
312
+ 'favicon' => $oCon->getPluginUrl_Image( 'pluginlogo_24x24.png' ),
313
  ),
314
  'flags' => array(
315
  'can_skip_mfa' => $oFO->getMfaSkipEnabled(),
325
  return true;
326
  }
327
 
328
+ /**
329
+ */
330
+ public function onWpLogout() {
331
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
332
+ $oFO = $this->getMod();
333
+
334
+ $this->removeLoginIntent();
335
+
336
+ // support for WooCommerce Social Login
337
+ if ( $oFO->getIfSupport3rdParty() ) {
338
+ $this->getController()->getCurrentUserMeta()->wc_social_login_valid = false;
339
+ }
340
+ }
341
+
342
  /**
343
  * @return ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth
344
  */
359
  return $oProc->setLoginTrack( $this->getLoginTrack() );
360
  }
361
 
362
+ /**
363
+ * @return ICWP_WPSF_Processor_LoginProtect_BackupCodes
364
+ */
365
+ public function getProcessorBackupCodes() {
366
+ require_once( dirname( __FILE__ ).'/loginprotect_backupcodes.php' );
367
+ $oProc = new ICWP_WPSF_Processor_LoginProtect_BackupCodes( $this->getMod() );
368
+ return $oProc->setLoginTrack( $this->getLoginTrack() );
369
+ }
370
+
371
  /**
372
  * @return ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator
373
  */
401
  $this->setLoginIntentProcessed();
402
  }
403
  $oTrk = $this->getLoginTrack();
404
+
405
+ // 1st: if backup code was used, then chained auth is irrelevant
406
+ $sBackupStub = ICWP_WPSF_Processor_LoginProtect_Track::Factor_BackupCode;
407
+
408
+ // if backup code used, that's successful; or
409
+ // It's not chained and you have any 1 successful; or
410
+ // It's chained (and then you must exclude the backup code.
411
+ $bSuccess = in_array( $sBackupStub, $oTrk->getFactorsSuccessful() )
412
+ || ( !$oFO->isChainedAuth() && $oTrk->hasSuccessfulFactor() );
413
+ if ( !$bSuccess && $oFO->isChainedAuth() ) {
414
+ $bSuccess = !$oTrk->hasUnSuccessfulFactor()
415
+ || ( $oTrk->getCountFactorsUnsuccessful() == 1 && in_array( $sBackupStub, $oTrk->getFactorsUnsuccessful() ) );
416
+ }
417
+
418
+ return $bSuccess;
419
  }
420
 
421
  /**
src/processors/loginprotect_intentprovider_base.php CHANGED
@@ -27,7 +27,7 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
27
  }
28
 
29
  if ( $this->loadWp()->isRequestUserLogin() || $oFO->getIfSupport3rdParty() ) {
30
- add_filter( 'authenticate', array( $this, 'processLoginAttempt_Filter' ), 30, 2 );
31
  }
32
 
33
  // Necessary so we don't show user intent to people without it
@@ -37,11 +37,29 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
37
  add_action( 'personal_options_update', array( $this, 'handleUserProfileSubmit' ) );
38
 
39
  if ( $this->getController()->isValidAdminArea( true ) ) {
40
- add_action( 'edit_user_profile', array( $this, 'addOptionsToUserProfile' ) );
41
  add_action( 'edit_user_profile_update', array( $this, 'handleEditOtherUserProfileSubmit' ) );
42
  }
43
  }
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  /**
46
  * @param WP_User $oUser
47
  */
@@ -53,14 +71,16 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
53
  $oLoginTrack->removeFactorToTrack( $sFactor );
54
  }
55
  else {
56
- if ( $this->processOtp( $oUser, $this->fetchCodeFromRequest() ) ) {
 
 
57
  $oLoginTrack->addSuccessfulFactor( $sFactor );
58
- $this->auditLogin( $oUser, true );
59
  }
60
  else {
61
  $oLoginTrack->addUnSuccessfulFactor( $sFactor );
62
- $this->auditLogin( $oUser, false );
63
  }
 
 
64
  }
65
  }
66
 
@@ -79,6 +99,7 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
79
  protected function hasValidatedProfile( $oUser ) {
80
  $sKey = $this->getStub().'_validated';
81
  return ( $oUser instanceof WP_User )
 
82
  && $this->loadWpUsers()->metaVoForUser( $this->prefix(), $oUser->ID )->{$sKey} === true;
83
  }
84
 
@@ -119,11 +140,22 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
119
  return !empty( $sSecret ) && is_string( $sSecret );
120
  }
121
 
 
 
 
 
 
 
 
 
 
 
 
122
  /**
123
  * @param WP_User $oUser
124
  * @return string
125
  */
126
- protected function resetSecret( WP_User $oUser ) {
127
  $sNewSecret = $this->genNewSecret();
128
  $this->setSecret( $oUser, $sNewSecret );
129
  return $sNewSecret;
@@ -181,6 +213,14 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
181
  public function addOptionsToUserProfile( $oUser ) {
182
  }
183
 
 
 
 
 
 
 
 
 
184
  /**
185
  * The only thing we can do is REMOVE Google Authenticator from an account that is not our own
186
  * But, only admins can do this. If Security Admin feature is enabled, then only they can do it.
@@ -223,6 +263,19 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends ICWP_
223
  */
224
  abstract protected function auditLogin( $oUser, $bIsSuccess );
225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  /**
227
  * @return string
228
  */
27
  }
28
 
29
  if ( $this->loadWp()->isRequestUserLogin() || $oFO->getIfSupport3rdParty() ) {
30
+ // add_filter( 'authenticate', array( $this, 'processLoginAttempt_Filter' ), 30, 2 );
31
  }
32
 
33
  // Necessary so we don't show user intent to people without it
37
  add_action( 'personal_options_update', array( $this, 'handleUserProfileSubmit' ) );
38
 
39
  if ( $this->getController()->isValidAdminArea( true ) ) {
40
+ add_action( 'edit_user_profile', array( $this, 'addOptionsToUserEditProfile' ) );
41
  add_action( 'edit_user_profile_update', array( $this, 'handleEditOtherUserProfileSubmit' ) );
42
  }
43
  }
44
 
45
+ /**
46
+ * @param string $sUsername
47
+ * @param WP_User $oUser
48
+ */
49
+ public function onWpLogin( $sUsername, $oUser ) {
50
+ $this->processLoginAttempt_Filter( $oUser );
51
+ }
52
+
53
+ /**
54
+ * @param string $sCookie
55
+ * @param int $nExpire
56
+ * @param int $nExpiration
57
+ * @param int $nUserId
58
+ */
59
+ public function onWpSetLoggedInCookie( $sCookie, $nExpire, $nExpiration, $nUserId ) {
60
+ $this->processLoginAttempt_Filter( $this->loadWpUsers()->getUserById( $nUserId ) );
61
+ }
62
+
63
  /**
64
  * @param WP_User $oUser
65
  */
71
  $oLoginTrack->removeFactorToTrack( $sFactor );
72
  }
73
  else {
74
+ $sReqOtpCode = $this->fetchCodeFromRequest();
75
+ $bOtpSuccess = $this->processOtp( $oUser, $sReqOtpCode );
76
+ if ( $bOtpSuccess ) {
77
  $oLoginTrack->addSuccessfulFactor( $sFactor );
 
78
  }
79
  else {
80
  $oLoginTrack->addUnSuccessfulFactor( $sFactor );
 
81
  }
82
+
83
+ $this->postOtpProcessAction( $oUser, $bOtpSuccess, !empty( $sReqOtpCode ) );
84
  }
85
  }
86
 
99
  protected function hasValidatedProfile( $oUser ) {
100
  $sKey = $this->getStub().'_validated';
101
  return ( $oUser instanceof WP_User )
102
+ && $this->hasValidSecret( $oUser )
103
  && $this->loadWpUsers()->metaVoForUser( $this->prefix(), $oUser->ID )->{$sKey} === true;
104
  }
105
 
140
  return !empty( $sSecret ) && is_string( $sSecret );
141
  }
142
 
143
+ /**
144
+ * @param WP_User $oUser
145
+ * @return $this
146
+ */
147
+ public function deleteSecret( $oUser ) {
148
+ $oMeta = $this->loadWpUsers()->metaVoForUser( $this->prefix(), $oUser->ID );
149
+ $sKey = $this->getStub().'_secret';
150
+ $oMeta->{$sKey} = null;
151
+ return $this;
152
+ }
153
+
154
  /**
155
  * @param WP_User $oUser
156
  * @return string
157
  */
158
+ public function resetSecret( WP_User $oUser ) {
159
  $sNewSecret = $this->genNewSecret();
160
  $this->setSecret( $oUser, $sNewSecret );
161
  return $sNewSecret;
213
  public function addOptionsToUserProfile( $oUser ) {
214
  }
215
 
216
+ /**
217
+ * ONLY TO BE HOOKED TO USER PROFILE EDIT
218
+ * @param WP_User $oUser
219
+ */
220
+ public function addOptionsToUserEditProfile( $oUser ) {
221
+ $this->addOptionsToUserProfile( $oUser );
222
+ }
223
+
224
  /**
225
  * The only thing we can do is REMOVE Google Authenticator from an account that is not our own
226
  * But, only admins can do this. If Security Admin feature is enabled, then only they can do it.
263
  */
264
  abstract protected function auditLogin( $oUser, $bIsSuccess );
265
 
266
+ /**
267
+ * @param WP_User $oUser
268
+ * @param bool $bIsOtpSuccess
269
+ * @param bool $bOtpProvided - whether a OTP was actually provided
270
+ * @return $this
271
+ */
272
+ protected function postOtpProcessAction( $oUser, $bIsOtpSuccess, $bOtpProvided ) {
273
+ if ( $bOtpProvided ) {
274
+ $this->auditLogin( $oUser, $bIsOtpSuccess );
275
+ }
276
+ return $this;
277
+ }
278
+
279
  /**
280
  * @return string
281
  */
src/processors/loginprotect_track.php CHANGED
@@ -9,6 +9,7 @@ class ICWP_WPSF_Processor_LoginProtect_Track {
9
  const Factor_Google_Authenticator = 'ga';
10
  const Factor_Yubikey = 'yubi';
11
  const Factor_Email = 'email';
 
12
 
13
  /**
14
  * @var array
@@ -80,7 +81,21 @@ class ICWP_WPSF_Processor_LoginProtect_Track {
80
  * @return int
81
  */
82
  public function getCountFactorsSuccessful() {
83
- return count( array_filter( $this->getAuthFactorsTracked() ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  }
85
 
86
  /**
9
  const Factor_Google_Authenticator = 'ga';
10
  const Factor_Yubikey = 'yubi';
11
  const Factor_Email = 'email';
12
+ const Factor_BackupCode = 'backupcode';
13
 
14
  /**
15
  * @var array
81
  * @return int
82
  */
83
  public function getCountFactorsSuccessful() {
84
+ return count( $this->getFactorsSuccessful() );
85
+ }
86
+
87
+ /**
88
+ * @return array
89
+ */
90
+ public function getFactorsSuccessful() {
91
+ return array_keys( array_filter( $this->getAuthFactorsTracked() ) ); // filter out the 'falses'
92
+ }
93
+
94
+ /**
95
+ * @return array
96
+ */
97
+ public function getFactorsUnsuccessful() {
98
+ return array_diff( array_keys( $this->getAuthFactorsTracked() ), $this->getFactorsSuccessful() );
99
  }
100
 
101
  /**
src/processors/loginprotect_twofactorauth.php CHANGED
@@ -17,16 +17,17 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
17
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
18
  $oFO = $this->getMod();
19
 
20
- $bLoginSuccess = is_object( $oUser ) && ( $oUser instanceof WP_User );
21
- if ( $bLoginSuccess && $this->hasValidatedProfile( $oUser ) && !$oFO->canUserMfaSkip( $oUser ) ) {
22
 
23
- // Now send email with authentication link for user.
24
- $this->doStatIncrement( 'login.twofactor.started' );
25
-
26
- $oMeta = $this->loadWpUsers()->metaVoForUser( $this->prefix(), $oUser->ID );
27
- $oMeta->code_tfaemail = $this->getSessionHashCode();
28
 
29
- $this->sendEmailTwoFactorVerify( $oUser );
 
 
 
30
  }
31
  return $oUser;
32
  }
@@ -38,19 +39,19 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
38
  protected function auditLogin( $oUser, $bIsSuccess ) {
39
  if ( $bIsSuccess ) {
40
  $this->addToAuditEntry(
41
- sprintf(
42
- _wpsf__( 'User "%s" verified their identity using Email Two-Factor Authentication.' ),
43
- $oUser->user_login ), 2, 'login_protect_two_factor_verified'
44
  );
45
- $this->doStatIncrement( 'login.twofactor.verified' );
46
  }
47
  else {
48
  $this->addToAuditEntry(
49
- sprintf(
50
- _wpsf__( 'User "%s" failed to verify their identity using Email Two-Factor Authentication.' ),
51
- $oUser->user_login ), 2, 'login_protect_two_factor_failed'
52
  );
53
- $this->doStatIncrement( 'login.twofactor.failed' );
54
  }
55
  }
56
 
@@ -60,9 +61,13 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
60
  * @return bool
61
  */
62
  protected function processOtp( $oUser, $sOtpCode ) {
63
- $bValid = ( $sOtpCode == $this->getStoredSessionHashCode() );
64
  if ( $bValid ) {
65
- unset( $this->loadWpUsers()->metaVoForUser( $this->prefix() )->code_tfaemail );
 
 
 
 
66
  }
67
  return $bValid;
68
  }
@@ -89,7 +94,7 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
89
  * @param WP_User $oUser
90
  * @return bool
91
  */
92
- public function hasValidatedProfile( $oUser ) {
93
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
94
  $oFO = $this->getMod();
95
  // Currently it's a global setting but this will evolve to be like Google Authenticator so that it's a user meta
@@ -120,9 +125,11 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
120
  }
121
 
122
  /**
123
- * @return string The unique 2FA 6-digit code
 
 
124
  */
125
- protected function getSessionHashCode() {
126
  return strtoupper( substr( $this->genSessionHash(), 0, 6 ) );
127
  }
128
 
@@ -130,7 +137,9 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
130
  * @return string The unique 2FA 6-digit code
131
  */
132
  protected function getStoredSessionHashCode() {
133
- return $this->getCurrentUserMeta()->code_tfaemail;
 
 
134
  }
135
 
136
  /**
@@ -138,26 +147,25 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
138
  * @return bool
139
  */
140
  protected function isSecretValid( $sSecret ) {
141
- return true; // we don't use individual user secrets for email (yet)
 
142
  }
143
 
144
  /**
145
  * @param WP_User $oUser
146
- * @return boolean
147
  */
148
  protected function sendEmailTwoFactorVerify( WP_User $oUser ) {
149
- $oWp = $this->loadWp();
150
  $sIpAddress = $this->ip();
151
- $sEmail = $oUser->get( 'user_email' );
152
 
153
  $aMessage = array(
154
  _wpsf__( 'Someone attempted to login into this WordPress site using your account.' ),
155
  _wpsf__( 'Login requires verification with the following code.' ),
156
  '',
157
- sprintf( _wpsf__( 'Verification Code: %s' ), sprintf( '<strong>%s</strong>', $this->getSessionHashCode() ) ),
158
  '',
159
  sprintf( '<strong>%s</strong>', _wpsf__( 'Login Details' ) ),
160
- sprintf( '%s: %s', _wpsf__( 'URL' ), $oWp->getHomeUrl() ),
161
  sprintf( '%s: %s', _wpsf__( 'Username' ), $oUser->user_login ),
162
  sprintf( '%s: %s', _wpsf__( 'IP Address' ), $sIpAddress ),
163
  '',
@@ -171,7 +179,7 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
171
  $sEmailSubject = _wpsf__( 'Two-Factor Login Verification' );
172
 
173
  $bResult = $this->getEmailProcessor()
174
- ->sendEmailWithWrap( $sEmail, $sEmailSubject, $aMessage );
175
  if ( $bResult ) {
176
  $sAuditMessage = sprintf( _wpsf__( 'User "%s" was sent an email to verify their Identity using Two-Factor Login Auth for IP address "%s".' ), $oUser->user_login, $sIpAddress );
177
  $this->addToAuditEntry( $sAuditMessage, 2, 'login_protect_two_factor_email_send' );
@@ -180,7 +188,7 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
180
  $sAuditMessage = sprintf( _wpsf__( 'Tried to send email to User "%s" to verify their identity using Two-Factor Login Auth for IP address "%s", but email sending failed.' ), $oUser->user_login, $sIpAddress );
181
  $this->addToAuditEntry( $sAuditMessage, 3, 'login_protect_two_factor_email_send_fail' );
182
  }
183
- return $bResult;
184
  }
185
 
186
  /**
17
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
18
  $oFO = $this->getMod();
19
 
20
+ if ( !$this->isLoginCaptured() && $oUser instanceof WP_User
21
+ && $this->hasValidatedProfile( $oUser ) && !$oFO->canUserMfaSkip( $oUser ) ) {
22
 
23
+ $oFO->getSessionsProcessor()
24
+ ->getQueryUpdater()
25
+ ->setLoginIntentCodeEmail( $oFO->getSession(), $this->getSecret( $oUser ) );
 
 
26
 
27
+ // Now send email with authentication link for user.
28
+ $this->doStatIncrement( 'login.twofactor.started' )
29
+ ->sendEmailTwoFactorVerify( $oUser )
30
+ ->setLoginCaptured();
31
  }
32
  return $oUser;
33
  }
39
  protected function auditLogin( $oUser, $bIsSuccess ) {
40
  if ( $bIsSuccess ) {
41
  $this->addToAuditEntry(
42
+ sprintf( _wpsf__( 'User "%s" verified their identity using %s method.' ),
43
+ $oUser->user_login, _wpsf__( 'Email Auth' )
44
+ ), 2, 'login_protect_emailauth_verified'
45
  );
46
+ $this->doStatIncrement( 'login.emailauth.verified' );
47
  }
48
  else {
49
  $this->addToAuditEntry(
50
+ sprintf( _wpsf__( 'User "%s" failed to verify their identity using %s method.' ),
51
+ $oUser->user_login, _wpsf__( 'Email Auth' )
52
+ ), 2, 'login_protect_emailauth_failed'
53
  );
54
+ $this->doStatIncrement( 'login.emailauth.failed' );
55
  }
56
  }
57
 
61
  * @return bool
62
  */
63
  protected function processOtp( $oUser, $sOtpCode ) {
64
+ $bValid = !empty( $sOtpCode ) && ( $sOtpCode == $this->getStoredSessionHashCode() );
65
  if ( $bValid ) {
66
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
67
+ $oFO = $this->getMod();
68
+ $oFO->getSessionsProcessor()
69
+ ->getQueryUpdater()
70
+ ->clearLoginIntentCodeEmail( $oFO->getSession() );
71
  }
72
  return $bValid;
73
  }
94
  * @param WP_User $oUser
95
  * @return bool
96
  */
97
+ protected function hasValidatedProfile( $oUser ) {
98
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
99
  $oFO = $this->getMod();
100
  // Currently it's a global setting but this will evolve to be like Google Authenticator so that it's a user meta
125
  }
126
 
127
  /**
128
+ * We don't use user meta as it's dependent on the particular user sessions in-use
129
+ * @param WP_User $oUser
130
+ * @return string
131
  */
132
+ protected function getSecret( WP_User $oUser ) {
133
  return strtoupper( substr( $this->genSessionHash(), 0, 6 ) );
134
  }
135
 
137
  * @return string The unique 2FA 6-digit code
138
  */
139
  protected function getStoredSessionHashCode() {
140
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
141
+ $oFO = $this->getMod();
142
+ return $oFO->hasSession() ? $oFO->getSession()->getLoginIntentCodeEmail() : '';
143
  }
144
 
145
  /**
147
  * @return bool
148
  */
149
  protected function isSecretValid( $sSecret ) {
150
+ $sHash = $this->getStoredSessionHashCode();
151
+ return !empty( $sHash );
152
  }
153
 
154
  /**
155
  * @param WP_User $oUser
156
+ * @return $this
157
  */
158
  protected function sendEmailTwoFactorVerify( WP_User $oUser ) {
 
159
  $sIpAddress = $this->ip();
 
160
 
161
  $aMessage = array(
162
  _wpsf__( 'Someone attempted to login into this WordPress site using your account.' ),
163
  _wpsf__( 'Login requires verification with the following code.' ),
164
  '',
165
+ sprintf( _wpsf__( 'Verification Code: %s' ), sprintf( '<strong>%s</strong>', $this->getSecret( $oUser ) ) ),
166
  '',
167
  sprintf( '<strong>%s</strong>', _wpsf__( 'Login Details' ) ),
168
+ sprintf( '%s: %s', _wpsf__( 'URL' ), $this->loadWp()->getHomeUrl() ),
169
  sprintf( '%s: %s', _wpsf__( 'Username' ), $oUser->user_login ),
170
  sprintf( '%s: %s', _wpsf__( 'IP Address' ), $sIpAddress ),
171
  '',
179
  $sEmailSubject = _wpsf__( 'Two-Factor Login Verification' );
180
 
181
  $bResult = $this->getEmailProcessor()
182
+ ->sendEmailWithWrap( $oUser->user_email, $sEmailSubject, $aMessage );
183
  if ( $bResult ) {
184
  $sAuditMessage = sprintf( _wpsf__( 'User "%s" was sent an email to verify their Identity using Two-Factor Login Auth for IP address "%s".' ), $oUser->user_login, $sIpAddress );
185
  $this->addToAuditEntry( $sAuditMessage, 2, 'login_protect_two_factor_email_send' );
188
  $sAuditMessage = sprintf( _wpsf__( 'Tried to send email to User "%s" to verify their identity using Two-Factor Login Auth for IP address "%s", but email sending failed.' ), $oUser->user_login, $sIpAddress );
189
  $this->addToAuditEntry( $sAuditMessage, 3, 'login_protect_two_factor_email_send_fail' );
190
  }
191
+ return $this;
192
  }
193
 
194
  /**
src/processors/loginprotect_wplogin.php CHANGED
@@ -14,7 +14,7 @@ class ICWP_WPSF_Processor_LoginProtect_WpLogin extends ICWP_WPSF_Processor_BaseW
14
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
15
  $oFO = $this->getMod();
16
 
17
- if ( !$oFO->getIsCustomLoginPathEnabled() || $this->checkForPluginConflict() || $this->checkForUnsupportedConfiguration() ) {
18
  return;
19
  }
20
 
14
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
15
  $oFO = $this->getMod();
16
 
17
+ if ( !$oFO->isCustomLoginPathEnabled() || $this->checkForPluginConflict() || $this->checkForUnsupportedConfiguration() ) {
18
  return;
19
  }
20
 
src/processors/loginprotect_yubikey.php CHANGED
@@ -236,15 +236,17 @@ class ICWP_WPSF_Processor_LoginProtect_Yubikey extends ICWP_WPSF_Processor_Login
236
  protected function auditLogin( $oUser, $bIsSuccess ) {
237
  if ( $bIsSuccess ) {
238
  $this->addToAuditEntry(
239
- sprintf( _wpsf__( 'User "%s" successfully logged in using a validated Yubikey One Time Password.' ),
240
- $oUser->user_login ), 2, 'login_protect_yubikey_login_success'
 
241
  );
242
  $this->doStatIncrement( 'login.yubikey.verified' );
243
  }
244
  else {
245
  $this->addToAuditEntry(
246
- sprintf( _wpsf__( 'User "%s" failed to verify their identity using Yubikey One Time Password.' ),
247
- $oUser->user_login ), 2, 'login_protect_yubikey_failed'
 
248
  );
249
  $this->doStatIncrement( 'login.yubikey.failed' );
250
  }
236
  protected function auditLogin( $oUser, $bIsSuccess ) {
237
  if ( $bIsSuccess ) {
238
  $this->addToAuditEntry(
239
+ sprintf( _wpsf__( 'User "%s" verified their identity using %s method.' ),
240
+ $oUser->user_login, _wpsf__( 'Yubikey OTP' )
241
+ ), 2, 'login_protect_yubikey_login_success'
242
  );
243
  $this->doStatIncrement( 'login.yubikey.verified' );
244
  }
245
  else {
246
  $this->addToAuditEntry(
247
+ sprintf( _wpsf__( 'User "%s" failed to verify their identity using %s method.' ),
248
+ $oUser->user_login, _wpsf__( 'Yubikey OTP' )
249
+ ),2, 'login_protect_yubikey_failed'
250
  );
251
  $this->doStatIncrement( 'login.yubikey.failed' );
252
  }
src/processors/plugin.php CHANGED
@@ -56,6 +56,8 @@ class ICWP_WPSF_Processor_Plugin extends ICWP_WPSF_Processor_BasePlugin {
56
  default:
57
  break;
58
  }
 
 
59
  }
60
 
61
  public function onWpLoaded() {
@@ -115,6 +117,34 @@ class ICWP_WPSF_Processor_Plugin extends ICWP_WPSF_Processor_BasePlugin {
115
  return $oProc;
116
  }
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  /**
119
  */
120
  public function dumpTrackingData() {
@@ -209,9 +239,9 @@ class ICWP_WPSF_Processor_Plugin extends ICWP_WPSF_Processor_BasePlugin {
209
  'forceOff',
210
  $oCon->getHumanName()
211
  ),
212
- 'delete' => _wpsf__( 'Click here to automatically delete the file' )
213
  ),
214
- 'ajax' => array(
215
  'delete_forceoff' => $oFO->getAjaxActionData( 'delete_forceoff', true )
216
  )
217
  );
56
  default:
57
  break;
58
  }
59
+
60
+ add_action( 'admin_footer', array( $this, 'printPluginDeactivateSurvey' ), 100, 0 );
61
  }
62
 
63
  public function onWpLoaded() {
117
  return $oProc;
118
  }
119
 
120
+ public function printPluginDeactivateSurvey() {
121
+ $oWp = $this->loadWp();
122
+ if ( $oWp->isCurrentPage( 'plugins.php' ) ) {
123
+
124
+ $aOpts = array(
125
+ 'reason_confusing' => "It's too confusing",
126
+ 'reason_expected' => "It's not what I expected",
127
+ 'reason_accident' => "I downloaded it accidentally",
128
+ 'reason_alternative' => "I'm already using an alternative",
129
+ 'reason_trust' => "I don't trust the developer :(",
130
+ 'reason_not_work' => "It doesn't work",
131
+ 'reason_errors' => "I'm getting errors",
132
+ );
133
+
134
+ $aRenderData = array(
135
+ 'strings' => array(
136
+ 'editing_restricted' => _wpsf__( 'Editing this option is currently restricted.' ),
137
+ ),
138
+ 'inputs' => array(
139
+ 'checkboxes' => $this->loadDP()->shuffleArray( $aOpts )
140
+ ),
141
+ 'js_snippets' => array()
142
+ );
143
+ echo $this->getMod()
144
+ ->renderTemplate( 'snippets/plugin-deactivate-survey.php', $aRenderData );
145
+ }
146
+ }
147
+
148
  /**
149
  */
150
  public function dumpTrackingData() {
239
  'forceOff',
240
  $oCon->getHumanName()
241
  ),
242
+ 'delete' => _wpsf__( 'Click here to automatically delete the file' )
243
  ),
244
+ 'ajax' => array(
245
  'delete_forceoff' => $oFO->getAjaxActionData( 'delete_forceoff', true )
246
  )
247
  );
src/processors/sessions.php CHANGED
@@ -18,11 +18,6 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
18
  */
19
  private $oCurrent;
20
 
21
- /**
22
- * @var int
23
- */
24
- private $nSessionAlreadyCreatedUserId = 0;
25
-
26
  /**
27
  * @param ICWP_WPSF_Processor_Sessions $oModCon
28
  */
@@ -85,8 +80,8 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
85
  $oFO = $this->getMod();
86
  if ( !$oFO->hasSession() && $oFO->isAutoAddSessions() ) {
87
  $this->queryCreateSession(
88
- $this->loadWpUsers()->getCurrentWpUsername(),
89
- $oFO->getConn()->getSessionId( true )
90
  );
91
  }
92
  }
@@ -125,13 +120,13 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
125
  if ( !$this->isLoginCaptured() && $oUser instanceof WP_User ) {
126
  $this->setLoginCaptured();
127
  // If they have a currently active session, terminate it (i.e. we replace it)
128
- $oSession = $this->queryGetSession( $oUser->user_login, $this->getSessionId() );
129
  if ( !empty( $oSession ) ) {
130
  $this->queryTerminateSession( $oSession );
131
- $this->oCurrent = null;
132
  }
133
 
134
- $this->queryCreateSession( $oUser->user_login, $this->getSessionId() );
135
  }
136
  return true;
137
  }
@@ -153,7 +148,7 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
153
 
154
  $mResult = $this->queryTerminateSession( $this->getCurrentSession() );
155
  $this->getController()->clearSession();
156
- $this->oCurrent = null;
157
  return $mResult;
158
  }
159
 
@@ -170,6 +165,8 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
170
  logged_in_at int(15) NOT NULL DEFAULT 0,
171
  last_activity_at int(15) UNSIGNED NOT NULL DEFAULT 0,
172
  last_activity_uri text NOT NULL DEFAULT '',
 
 
173
  secadmin_at int(15) UNSIGNED NOT NULL DEFAULT 0,
174
  created_at int(15) UNSIGNED NOT NULL DEFAULT 0,
175
  deleted_at int(15) UNSIGNED NOT NULL DEFAULT 0,
@@ -182,23 +179,30 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
182
  * @return ICWP_WPSF_SessionVO|null
183
  */
184
  public function getCurrentSession() {
185
- if ( is_null( $this->oCurrent ) ) {
186
  $this->oCurrent = $this->loadCurrentSession();
187
  }
188
  return $this->oCurrent;
189
  }
190
 
 
 
 
 
 
 
 
 
191
  /**
192
  * @return ICWP_WPSF_SessionVO|null
193
  */
194
  public function loadCurrentSession() {
195
  $oSession = null;
196
- $oWpUsers = $this->loadWpUsers();
197
- if ( did_action( 'init' ) && $oWpUsers->isUserLoggedIn() ) {
198
- $oUser = $oWpUsers->getCurrentWpUser();
199
- if ( $oUser instanceof WP_User ) {
200
- $oSession = $this->queryGetSession( $oUser->user_login, $this->getSessionId() );
201
- }
202
  }
203
  return $oSession;
204
  }
@@ -241,17 +245,17 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
241
  }
242
 
243
  /**
244
- * @param string $sUsername
245
  * @param string $sSessionId
 
246
  * @return bool
247
  */
248
- protected function queryCreateSession( $sUsername, $sSessionId ) {
249
- if ( empty( $sUsername ) ) {
250
  return null;
251
  }
252
 
253
  $bSuccess = $this->getQueryInserter()
254
- ->create( $sUsername, $sSessionId );
255
  if ( $bSuccess ) {
256
  $this->doStatIncrement( 'user.session.start' );
257
  }
@@ -264,9 +268,9 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
264
  * @param string $sSessionId
265
  * @return ICWP_WPSF_SessionVO|null
266
  */
267
- protected function queryGetSession( $sUsername, $sSessionId ) {
268
  return $this->getQuerySelector()
269
- ->retrieveUserSession( $sUsername, $sSessionId );
270
  }
271
 
272
  /**
18
  */
19
  private $oCurrent;
20
 
 
 
 
 
 
21
  /**
22
  * @param ICWP_WPSF_Processor_Sessions $oModCon
23
  */
80
  $oFO = $this->getMod();
81
  if ( !$oFO->hasSession() && $oFO->isAutoAddSessions() ) {
82
  $this->queryCreateSession(
83
+ $oFO->getConn()->getSessionId( true ),
84
+ $this->loadWpUsers()->getCurrentWpUsername()
85
  );
86
  }
87
  }
120
  if ( !$this->isLoginCaptured() && $oUser instanceof WP_User ) {
121
  $this->setLoginCaptured();
122
  // If they have a currently active session, terminate it (i.e. we replace it)
123
+ $oSession = $this->queryGetSession( $this->getSessionId(), $oUser->user_login );
124
  if ( !empty( $oSession ) ) {
125
  $this->queryTerminateSession( $oSession );
126
+ $this->clearCurrentSession();
127
  }
128
 
129
+ $this->queryCreateSession( $this->getSessionId(), $oUser->user_login );
130
  }
131
  return true;
132
  }
148
 
149
  $mResult = $this->queryTerminateSession( $this->getCurrentSession() );
150
  $this->getController()->clearSession();
151
+ $this->clearCurrentSession();
152
  return $mResult;
153
  }
154
 
165
  logged_in_at int(15) NOT NULL DEFAULT 0,
166
  last_activity_at int(15) UNSIGNED NOT NULL DEFAULT 0,
167
  last_activity_uri text NOT NULL DEFAULT '',
168
+ li_code_email varchar(6) NOT NULL DEFAULT '',
169
+ login_intent_expires_at int(15) UNSIGNED NOT NULL DEFAULT 0,
170
  secadmin_at int(15) UNSIGNED NOT NULL DEFAULT 0,
171
  created_at int(15) UNSIGNED NOT NULL DEFAULT 0,
172
  deleted_at int(15) UNSIGNED NOT NULL DEFAULT 0,
179
  * @return ICWP_WPSF_SessionVO|null
180
  */
181
  public function getCurrentSession() {
182
+ if ( empty( $this->oCurrent ) ) {
183
  $this->oCurrent = $this->loadCurrentSession();
184
  }
185
  return $this->oCurrent;
186
  }
187
 
188
+ /**
189
+ * @return $this
190
+ */
191
+ public function clearCurrentSession() {
192
+ $this->oCurrent = null;
193
+ return $this;
194
+ }
195
+
196
  /**
197
  * @return ICWP_WPSF_SessionVO|null
198
  */
199
  public function loadCurrentSession() {
200
  $oSession = null;
201
+ if ( did_action( 'init' ) ) {
202
+ $oSession = $this->queryGetSession(
203
+ $this->getSessionId(),
204
+ $this->loadWpUsers()->getCurrentWpUsername()
205
+ );
 
206
  }
207
  return $oSession;
208
  }
245
  }
246
 
247
  /**
 
248
  * @param string $sSessionId
249
+ * @param string $sUsername
250
  * @return bool
251
  */
252
+ protected function queryCreateSession( $sSessionId, $sUsername ) {
253
+ if ( empty( $sSessionId ) || empty( $sUsername ) ) {
254
  return null;
255
  }
256
 
257
  $bSuccess = $this->getQueryInserter()
258
+ ->create( $sSessionId, $sUsername );
259
  if ( $bSuccess ) {
260
  $this->doStatIncrement( 'user.session.start' );
261
  }
268
  * @param string $sSessionId
269
  * @return ICWP_WPSF_SessionVO|null
270
  */
271
+ protected function queryGetSession( $sSessionId, $sUsername = '' ) {
272
  return $this->getQuerySelector()
273
+ ->retrieveUserSession( $sSessionId, $sUsername );
274
  }
275
 
276
  /**
src/processors/traffic_logger.php CHANGED
@@ -51,6 +51,7 @@ class ICWP_WPSF_Processor_TrafficLogger extends ICWP_WPSF_BaseDbProcessor {
51
  $bLoggedIn = $this->loadWpUsers()->isUserLoggedIn();
52
  return parent::getIfLogRequest()
53
  && ( $oFO->getMaxEntries() > 0 )
 
54
  && ( $oFO->isIncluded_Simple() || count( $this->loadDP()->getRequestParams( false ) ) > 0 )
55
  && ( $oFO->isIncluded_LoggedInUser() || !$bLoggedIn )
56
  && ( $oFO->isIncluded_Ajax() || !$oWp->isAjax() )
@@ -65,207 +66,61 @@ class ICWP_WPSF_Processor_TrafficLogger extends ICWP_WPSF_BaseDbProcessor {
65
  }
66
 
67
  /**
68
- * Best to check for logged-in status before using this
69
  * @return bool
70
  */
71
- protected function isServiceIp() {
72
- return ( $this->isServiceIp_Uptime() || $this->isServiceIp_Search() );
73
- }
74
-
75
- /**
76
- * TODO: Other search engines
77
- * @return bool
78
- */
79
- protected function isServiceIp_Search() {
80
- $sIp = $this->ip();
81
  $sAgent = (string)$this->loadDP()->server( 'HTTP_USER_AGENT' );
82
- return $this->isIp_GoogleBot( $sIp, $sAgent )
83
- || $this->isIp_BingBot( $sIp, $sAgent )
84
- || $this->isIp_DuckDuckGoBot( $sIp, $sAgent )
85
- || $this->isIp_YandexBot( $sIp, $sAgent )
86
- || $this->isIp_AppleBot( $sIp, $sAgent );
87
- }
88
-
89
- /**
90
- * @return bool
91
- */
92
- protected function isServiceIp_Uptime() {
93
- $sIp = $this->ip();
94
- return $this->isIp_Statuscake( $sIp )
95
- || $this->isIp_UptimeRobot( $sIp )
96
- || $this->isIp_Pingdom( $sIp );
97
- }
98
 
99
- /**
100
- * @param string $sIp
101
- * @return bool
102
- */
103
- protected function isIp_Cloudflare( $sIp ) {
104
- return $this->loadIpService()->isCloudFlareIp( $sIp );
105
- }
106
-
107
- /**
108
- * @param string $sIp
109
- * @param string $sUserAgent
110
- * @return bool
111
- */
112
- protected function isIp_BingBot( $sIp, $sUserAgent ) {
113
- $oWp = $this->loadWp();
114
-
115
- $aIps = $oWp->getTransient( $this->prefix( 'serviceips_bingbot' ) );
116
- if ( !is_array( $aIps ) ) {
117
- $aIps = array();
118
  }
119
-
120
- if ( !in_array( $sIp, $aIps ) && $this->loadIpService()->isIpBingBot( $sIp, $sUserAgent ) ) {
121
- $aIps[] = $sIp;
122
- $aIps = $oWp->setTransient( $this->prefix( 'serviceips_bingbot' ), $aIps, WEEK_IN_SECONDS*4 );
123
- }
124
-
125
- return in_array( $sIp, $aIps );
126
- }
127
-
128
- /**
129
- * @param string $sIp
130
- * @param string $sUserAgent
131
- * @return bool
132
- */
133
- protected function isIp_DuckDuckGoBot( $sIp, $sUserAgent ) {
134
- return $this->loadIpService()->isIpDuckDuckGoBot( $sIp, $sUserAgent );
135
  }
136
 
137
  /**
138
- * https://support.google.com/webmasters/answer/80553?hl=en
139
- * @param string $sIp
140
- * @param string $sUserAgent
141
- * @return bool
142
- */
143
- protected function isIp_GoogleBot( $sIp, $sUserAgent ) {
144
- $oWp = $this->loadWp();
145
-
146
- $aIps = $oWp->getTransient( $this->prefix( 'serviceips_googlebot' ) );
147
- if ( !is_array( $aIps ) ) {
148
- $aIps = array();
149
- }
150
-
151
- if ( !in_array( $sIp, $aIps ) && $this->loadIpService()->isIpGoogleBot( $sIp, $sUserAgent ) ) {
152
- $aIps[] = $sIp;
153
- $aIps = $oWp->setTransient( $this->prefix( 'serviceips_googlebot' ), $aIps, WEEK_IN_SECONDS*4 );
154
- }
155
-
156
- return in_array( $sIp, $aIps );
157
- }
158
-
159
- /**
160
- * https://yandex.com/support/webmaster/robot-workings/check-yandex-robots.html
161
- * @param string $sIp
162
- * @param string $sUserAgent
163
- * @return bool
164
- */
165
- protected function isIp_YandexBot( $sIp, $sUserAgent ) {
166
- $oWp = $this->loadWp();
167
-
168
- $aIps = $oWp->getTransient( $this->prefix( 'serviceips_yandexbot' ) );
169
- if ( !is_array( $aIps ) ) {
170
- $aIps = array();
171
- }
172
-
173
- if ( !in_array( $sIp, $aIps ) && $this->loadIpService()->isIpYandexBot( $sIp, $sUserAgent ) ) {
174
- $aIps[] = $sIp;
175
- $aIps = $oWp->setTransient( $this->prefix( 'serviceips_yandexbot' ), $aIps, WEEK_IN_SECONDS*4 );
176
- }
177
-
178
- return in_array( $sIp, $aIps );
179
- }
180
-
181
- /**
182
- * @param string $sIp
183
- * @param string $sUserAgent
184
  * @return bool
185
  */
186
- protected function isIp_AppleBot( $sIp, $sUserAgent ) {
187
- $oWp = $this->loadWp();
188
-
189
- $aIps = $oWp->getTransient( $this->prefix( 'serviceips_applebot' ) );
190
- if ( !is_array( $aIps ) ) {
191
- $aIps = array();
192
- }
193
-
194
- if ( !in_array( $sIp, $aIps ) && $this->loadIpService()->isIpAppleBot( $sIp, $sUserAgent ) ) {
195
- $aIps[] = $sIp;
196
- $aIps = $oWp->setTransient( $this->prefix( 'serviceips_applebot' ), $aIps, WEEK_IN_SECONDS*4 );
197
- }
198
-
199
- return in_array( $sIp, $aIps );
200
  }
201
 
202
  /**
203
- * @param string $sIp
204
  * @return bool
205
  */
206
- protected function isIp_Statuscake( $sIp ) {
207
- return in_array( $sIp, $this->getIpsStatuscake() );
208
- }
209
 
210
- /**
211
- * @param string $sIp
212
- * @return bool
213
- */
214
- protected function isIp_Pingdom( $sIp ) {
215
- return in_array( $sIp, $this->getIpsPingdom()[ $this->loadIpService()->getIpVersion( $sIp ) ] );
 
 
 
216
  }
217
 
218
  /**
219
- * @param string $sIp
220
  * @return bool
221
  */
222
- protected function isIp_UptimeRobot( $sIp ) {
223
- return in_array( $sIp, $this->getIpsUptimeRobot()[ $this->loadIpService()->getIpVersion( $sIp ) ] );
224
- }
225
-
226
- /**
227
- * @return string[]
228
- */
229
- protected function getIpsStatuscake() {
230
- $oWp = $this->loadWp();
231
- $aIps = $oWp->getTransient( $this->prefix( 'serviceips_statuscake' ) );
232
- if ( empty( $aIps ) ) {
233
- $aIps = $this->loadIpService()->getServiceIps_StatusCake();
234
- $oWp->setTransient( $this->prefix( 'serviceips_statuscake' ), $aIps, WEEK_IN_SECONDS*4 );
235
- }
236
- return $aIps;
237
- }
238
-
239
- /**
240
- * @return array[]
241
- */
242
- protected function getIpsUptimeRobot() {
243
- $oWp = $this->loadWp();
244
- $aIps = $oWp->getTransient( $this->prefix( 'serviceips_uptimerobot' ) );
245
- if ( empty( $aIps ) ) {
246
- $aIps = array(
247
- 4 => $this->loadIpService()->getServiceIps_UptimeRobot( 4 ),
248
- 6 => $this->loadIpService()->getServiceIps_UptimeRobot( 6 )
249
- );
250
- $oWp->setTransient( $this->prefix( 'serviceips_uptimerobot' ), $aIps, WEEK_IN_SECONDS*4 );
251
- }
252
- return $aIps;
253
- }
254
 
255
- /**
256
- * @return array[]
257
- */
258
- protected function getIpsPingdom() {
259
- $oWp = $this->loadWp();
260
- $aIps = $oWp->getTransient( $this->prefix( 'serviceips_pingdom' ) );
261
- if ( empty( $aIps ) ) {
262
- $aIps = array(
263
- 4 => $this->loadIpService()->getServiceIps_Pingdom( 4 ),
264
- 6 => $this->loadIpService()->getServiceIps_Pingdom( 6 )
265
- );
266
- $oWp->setTransient( $this->prefix( 'serviceips_pingdom' ), $aIps, WEEK_IN_SECONDS*4 );
267
- }
268
- return $aIps;
269
  }
270
 
271
  protected function logTraffic() {
51
  $bLoggedIn = $this->loadWpUsers()->isUserLoggedIn();
52
  return parent::getIfLogRequest()
53
  && ( $oFO->getMaxEntries() > 0 )
54
+ && ( !$this->isCustomExcluded() )
55
  && ( $oFO->isIncluded_Simple() || count( $this->loadDP()->getRequestParams( false ) ) > 0 )
56
  && ( $oFO->isIncluded_LoggedInUser() || !$bLoggedIn )
57
  && ( $oFO->isIncluded_Ajax() || !$oWp->isAjax() )
66
  }
67
 
68
  /**
 
69
  * @return bool
70
  */
71
+ protected function isCustomExcluded() {
72
+ /** @var ICWP_WPSF_FeatureHandler_Traffic $oFO */
73
+ $oFO = $this->getMod();
74
+ $oDP = $this->loadDP();
75
+ $aExcls = $oFO->getCustomExclusions();
 
 
 
 
 
76
  $sAgent = (string)$this->loadDP()->server( 'HTTP_USER_AGENT' );
77
+ $sPath = $oDP->getRequestPath().( empty( $_GET ) ? '' : '?'.http_build_query( $_GET ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ $bExcluded = false;
80
+ foreach ( $aExcls as $sExcl ) {
81
+ if ( stripos( $sAgent, $sExcl ) !== false || stripos( $sPath, $sExcl ) !== false ) {
82
+ $bExcluded = true;
83
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  }
85
+ return $bExcluded;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  }
87
 
88
  /**
89
+ * Best to check for logged-in status before using this
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  * @return bool
91
  */
92
+ protected function isServiceIp() {
93
+ return ( $this->isServiceIp_Uptime() || $this->isServiceIp_Search() );
 
 
 
 
 
 
 
 
 
 
 
 
94
  }
95
 
96
  /**
 
97
  * @return bool
98
  */
99
+ protected function isServiceIp_Search() {
100
+ $oSP = $this->loadServiceProviders();
 
101
 
102
+ $sIp = $this->ip();
103
+ $sAgent = (string)$this->loadDP()->server( 'HTTP_USER_AGENT' );
104
+ return $oSP->isIp_GoogleBot( $sIp, $sAgent )
105
+ || $oSP->isIp_BingBot( $sIp, $sAgent )
106
+ || $oSP->isIp_DuckDuckGoBot( $sIp, $sAgent )
107
+ || $oSP->isIp_YandexBot( $sIp, $sAgent )
108
+ || $oSP->isIp_BaiduBot( $sIp, $sAgent )
109
+ || $oSP->isIp_YahooBot( $sIp, $sAgent )
110
+ || $oSP->isIp_AppleBot( $sIp, $sAgent );
111
  }
112
 
113
  /**
 
114
  * @return bool
115
  */
116
+ protected function isServiceIp_Uptime() {
117
+ $oSP = $this->loadServiceProviders();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
+ $sIp = $this->ip();
120
+ $sAgent = (string)$this->loadDP()->server( 'HTTP_USER_AGENT' );
121
+ return $oSP->isIp_Statuscake( $sIp, $sAgent )
122
+ || $oSP->isIp_UptimeRobot( $sIp, $sAgent )
123
+ || $oSP->isIp_Pingdom( $sIp, $sAgent );
 
 
 
 
 
 
 
 
 
124
  }
125
 
126
  protected function logTraffic() {
src/query/base/select.php CHANGED
@@ -117,13 +117,16 @@ class ICWP_WPSF_Query_BaseSelect extends ICWP_WPSF_Query_BaseQuery {
117
  */
118
  public function setColumnsToSelect( $aColumns ) {
119
  if ( is_array( $aColumns ) ) {
120
- $this->aColumnsToSelect = array_unique( array_filter(
121
- array_map( 'trim', $aColumns ),
122
- function ( $sCol ) {
123
- $aDef = $this->getColumnsDefinition();
124
- return !empty( $sCol ) && ( empty( $aDef ) || in_array( $sCol, $aDef ) );
 
 
125
  }
126
- ) );
 
127
  }
128
  return $this;
129
  }
117
  */
118
  public function setColumnsToSelect( $aColumns ) {
119
  if ( is_array( $aColumns ) ) {
120
+ $aColumns = array_filter( array_map( 'trim', $aColumns ) );
121
+ $aDef = $this->getColumnsDefinition();
122
+ if ( !empty( $aDef ) ) {
123
+ foreach ( $aColumns as $nKey => $sCol ) {
124
+ if ( !in_array( $sCol, $aDef ) ) {
125
+ unset( $aColumns[ $nKey ] );
126
+ }
127
  }
128
+ }
129
+ $this->aColumnsToSelect = array_unique( $aColumns );
130
  }
131
  return $this;
132
  }
src/query/sessions/ICWP_WPSF_SessionVO.php CHANGED
@@ -45,14 +45,28 @@ class ICWP_WPSF_SessionVO {
45
  * @return int
46
  */
47
  public function getLastActivityAt() {
48
- return $this->getRowData()->last_activity_at;
49
  }
50
 
51
  /**
52
  * @return int
53
  */
54
  public function getLoggedInAt() {
55
- return $this->getRowData()->logged_in_at;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  }
57
 
58
  /**
@@ -66,7 +80,7 @@ class ICWP_WPSF_SessionVO {
66
  * @return int
67
  */
68
  public function getSecAdminAt() {
69
- return $this->getRowData()->secadmin_at;
70
  }
71
 
72
  /**
45
  * @return int
46
  */
47
  public function getLastActivityAt() {
48
+ return (int)$this->getRowData()->last_activity_at;
49
  }
50
 
51
  /**
52
  * @return int
53
  */
54
  public function getLoggedInAt() {
55
+ return (int)$this->getRowData()->logged_in_at;
56
+ }
57
+
58
+ /**
59
+ * @return int
60
+ */
61
+ public function getLoginIntentExpiresAt() {
62
+ return (int)$this->getRowData()->login_intent_expires_at;
63
+ }
64
+
65
+ /**
66
+ * @return string
67
+ */
68
+ public function getLoginIntentCodeEmail() {
69
+ return (string)$this->getRowData()->li_code_email;
70
  }
71
 
72
  /**
80
  * @return int
81
  */
82
  public function getSecAdminAt() {
83
+ return (int)$this->getRowData()->secadmin_at;
84
  }
85
 
86
  /**
src/query/sessions/insert.php CHANGED
@@ -9,23 +9,25 @@ require_once( dirname( dirname( __FILE__ ) ).'/base/insert.php' );
9
  class ICWP_WPSF_Query_Sessions_Insert extends ICWP_WPSF_Query_BaseInsert {
10
 
11
  /**
12
- * @param string $sUsername
13
  * @param string $sSessionId
 
14
  * @return bool
15
  */
16
- public function create( $sUsername, $sSessionId ) {
17
  $oDP = $this->loadDP();
18
  $nTimeStamp = $oDP->time();
19
 
20
  $aData = array(
21
- 'session_id' => $sSessionId,
22
- 'ip' => $this->loadIpService()->getRequestIp(), // TODO: SHA1
23
- 'browser' => md5( $oDP->getUserAgent() ),
24
- 'wp_username' => $sUsername,
25
- 'logged_in_at' => $nTimeStamp,
26
- 'created_at' => $nTimeStamp,
27
- 'last_activity_at' => $nTimeStamp,
28
- 'last_activity_uri' => $oDP->server( 'REQUEST_URI' ),
 
 
29
  );
30
  return $this->setInsertData( $aData )->query() === 1;
31
  }
9
  class ICWP_WPSF_Query_Sessions_Insert extends ICWP_WPSF_Query_BaseInsert {
10
 
11
  /**
 
12
  * @param string $sSessionId
13
+ * @param string $sUsername
14
  * @return bool
15
  */
16
+ public function create( $sSessionId, $sUsername ) {
17
  $oDP = $this->loadDP();
18
  $nTimeStamp = $oDP->time();
19
 
20
  $aData = array(
21
+ 'session_id' => $sSessionId,
22
+ 'ip' => $this->loadIpService()->getRequestIp(), // TODO: SHA1
23
+ 'browser' => md5( $oDP->getUserAgent() ),
24
+ 'wp_username' => $sUsername,
25
+ 'logged_in_at' => $nTimeStamp,
26
+ 'created_at' => $nTimeStamp,
27
+ 'last_activity_at' => $nTimeStamp,
28
+ 'last_activity_uri' => $oDP->server( 'REQUEST_URI' ),
29
+ 'login_intent_expires_at' => 0,
30
+ 'secadmin_at' => 0,
31
  );
32
  return $this->setInsertData( $aData )->query() === 1;
33
  }
src/query/sessions/select.php CHANGED
@@ -25,21 +25,21 @@ class ICWP_WPSF_Query_Sessions_Select extends ICWP_WPSF_Query_BaseSelect {
25
  }
26
 
27
  /**
28
- * @param string $sWpUsername
29
  * @param string $sSessionId
 
30
  * @return ICWP_WPSF_SessionVO|null
31
  */
32
- public function retrieveUserSession( $sWpUsername, $sSessionId ) {
33
- $aData = $this->selectForUserSession( $sWpUsername, $sSessionId );
34
  return ( count( $aData ) == 1 ) ? array_shift( $aData ) : null;
35
  }
36
 
37
  /**
38
- * @param string $sWpUsername
39
  * @param string $sSessionId
 
40
  * @return ICWP_WPSF_SessionVO[]
41
  */
42
- protected function selectForUserSession( $sWpUsername = '', $sSessionId = '' ) {
43
  if ( !empty( $sWpUsername ) ) {
44
  $this->addWhereEquals( 'wp_username', $sWpUsername );
45
  }
25
  }
26
 
27
  /**
 
28
  * @param string $sSessionId
29
+ * @param string $sWpUsername
30
  * @return ICWP_WPSF_SessionVO|null
31
  */
32
+ public function retrieveUserSession( $sSessionId, $sWpUsername = '' ) {
33
+ $aData = $this->selectForUserSession( $sSessionId, $sWpUsername );
34
  return ( count( $aData ) == 1 ) ? array_shift( $aData ) : null;
35
  }
36
 
37
  /**
 
38
  * @param string $sSessionId
39
+ * @param string $sWpUsername
40
  * @return ICWP_WPSF_SessionVO[]
41
  */
42
+ protected function selectForUserSession( $sSessionId = '', $sWpUsername = '' ) {
43
  if ( !empty( $sWpUsername ) ) {
44
  $this->addWhereEquals( 'wp_username', $sWpUsername );
45
  }
src/query/sessions/update.php CHANGED
@@ -13,10 +13,7 @@ class ICWP_WPSF_Query_Sessions_Update extends ICWP_WPSF_Query_BaseUpdate {
13
  * @return bool
14
  */
15
  public function startSecurityAdmin( $oSession ) {
16
- return $this->updateSession(
17
- $oSession,
18
- array( 'secadmin_at' => $this->loadDP()->time() )
19
- );
20
  }
21
 
22
  /**
@@ -24,10 +21,7 @@ class ICWP_WPSF_Query_Sessions_Update extends ICWP_WPSF_Query_BaseUpdate {
24
  * @return bool
25
  */
26
  public function terminateSecurityAdmin( $oSession ) {
27
- return $this->updateSession(
28
- $oSession,
29
- array( 'secadmin_at' => 0 )
30
- );
31
  }
32
 
33
  /**
@@ -45,13 +39,42 @@ class ICWP_WPSF_Query_Sessions_Update extends ICWP_WPSF_Query_BaseUpdate {
45
  );
46
  }
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  /**
49
  * @param ICWP_WPSF_SessionVO $oSession
50
  * @param array $aUpdateData
51
  * @return bool
52
  */
53
  public function updateSession( $oSession, $aUpdateData = array() ) {
54
- $mResult = false;
55
  if ( !empty( $aUpdateData ) && $oSession instanceof ICWP_WPSF_SessionVO ) {
56
  $mResult = $this
57
  ->setUpdateData( $aUpdateData )
@@ -63,7 +86,15 @@ class ICWP_WPSF_Query_Sessions_Update extends ICWP_WPSF_Query_BaseUpdate {
63
  )
64
  )
65
  ->query();
 
 
 
 
 
 
 
66
  }
67
- return is_numeric( $mResult ) && $mResult === 1;
 
68
  }
69
  }
13
  * @return bool
14
  */
15
  public function startSecurityAdmin( $oSession ) {
16
+ return $this->updateSession( $oSession, array( 'secadmin_at' => $this->loadDP()->time() ) );
 
 
 
17
  }
18
 
19
  /**
21
  * @return bool
22
  */
23
  public function terminateSecurityAdmin( $oSession ) {
24
+ return $this->updateSession( $oSession, array( 'secadmin_at' => 0 ) );
 
 
 
25
  }
26
 
27
  /**
39
  );
40
  }
41
 
42
+ /**
43
+ * @param ICWP_WPSF_SessionVO $oSession
44
+ * @param int $nExpiresAt
45
+ * @return bool
46
+ */
47
+ public function updateLoginIntentExpiresAt( $oSession, $nExpiresAt ) {
48
+ return $this->updateSession(
49
+ $oSession,
50
+ array( 'login_intent_expires_at' => (int)$nExpiresAt )
51
+ );
52
+ }
53
+
54
+ /**
55
+ * @param ICWP_WPSF_SessionVO $oSession
56
+ * @return bool
57
+ */
58
+ public function clearLoginIntentCodeEmail( $oSession ) {
59
+ return $this->setLoginIntentCodeEmail( $oSession, '' );
60
+ }
61
+
62
+ /**
63
+ * @param ICWP_WPSF_SessionVO $oSession
64
+ * @param string $sCode
65
+ * @return bool
66
+ */
67
+ public function setLoginIntentCodeEmail( $oSession, $sCode ) {
68
+ return $this->updateSession( $oSession, array( 'li_code_email' => (string)$sCode ) );
69
+ }
70
+
71
  /**
72
  * @param ICWP_WPSF_SessionVO $oSession
73
  * @param array $aUpdateData
74
  * @return bool
75
  */
76
  public function updateSession( $oSession, $aUpdateData = array() ) {
77
+ $bSuccess = false;
78
  if ( !empty( $aUpdateData ) && $oSession instanceof ICWP_WPSF_SessionVO ) {
79
  $mResult = $this
80
  ->setUpdateData( $aUpdateData )
86
  )
87
  )
88
  ->query();
89
+ $bSuccess = is_numeric( $mResult ) && $mResult === 1;
90
+
91
+ if ( $bSuccess ) {
92
+ foreach ( $aUpdateData as $sColumn => $mValue ) {
93
+ $oSession->{$sColumn} = $mValue;
94
+ }
95
+ }
96
  }
97
+
98
+ return $bSuccess;
99
  }
100
  }
src/wizards/base_wpsf.php CHANGED
@@ -113,7 +113,7 @@ abstract class ICWP_WPSF_Wizard_BaseWpsf extends ICWP_WPSF_Wizard_Base {
113
  $sMessage = _wpsf__( 'Security Admin Key was not correct.' );
114
  }
115
  else {
116
- $bSuccess = $oModule->setPermissionToSubmit( true );
117
  $aData = array(
118
  'rerender' => true
119
  );
113
  $sMessage = _wpsf__( 'Security Admin Key was not correct.' );
114
  }
115
  else {
116
+ $bSuccess = $oModule->setSecurityAdminStatusOnOff( true );
117
  $aData = array(
118
  'rerender' => true
119
  );
src/wizards/login_protect.php CHANGED
@@ -64,8 +64,10 @@ class ICWP_WPSF_Wizard_LoginProtect extends ICWP_WPSF_Wizard_BaseWpsf {
64
  else {
65
  if ( empty( $sCode ) ) {
66
  if ( $oFO->sendEmailVerifyCanSend( $sEmail, false ) ) {
 
67
  $oResponse->setSuccessful( true );
68
- $sMessage = 'Verification email sent - please check your email (including your SPAM)';
 
69
  }
70
  else {
71
  $sMessage = 'Failed to send verification email';
@@ -195,7 +197,7 @@ class ICWP_WPSF_Wizard_LoginProtect extends ICWP_WPSF_Wizard_BaseWpsf {
195
  $aStepsSlugs[] = 'authemail';
196
  }
197
 
198
- if ( !$oFO->getIsEnabledGoogleAuthenticator() ) {
199
  $aStepsSlugs[] = 'authga';
200
  }
201
 
64
  else {
65
  if ( empty( $sCode ) ) {
66
  if ( $oFO->sendEmailVerifyCanSend( $sEmail, false ) ) {
67
+ $oFO->setIfCanSendEmail( false );
68
  $oResponse->setSuccessful( true );
69
+ $sMessage = _wpsf__( 'Verification email sent (please check your email including your SPAM).' )
70
+ .' '._wpsf__( 'Enter the code from the email into the form above and click the button to verify.' );
71
  }
72
  else {
73
  $sMessage = 'Failed to send verification email';
197
  $aStepsSlugs[] = 'authemail';
198
  }
199
 
200
+ if ( !$oFO->isEnabledGoogleAuthenticator() ) {
201
  $aStepsSlugs[] = 'authga';
202
  }
203
 
src/wizards/plugin.php CHANGED
@@ -457,7 +457,7 @@ class ICWP_WPSF_Wizard_Plugin extends ICWP_WPSF_Wizard_BaseWpsf {
457
  $oModule = $this->getPluginCon()->getModule( 'admin_access_restriction' );
458
  try {
459
  $oModule->setNewAccessKeyManually( $sKey )
460
- ->setPermissionToSubmit( true );
461
  $bSuccess = true;
462
  $sMessage = _wpsf__( 'Security Admin setup was successful.' );
463
  }
457
  $oModule = $this->getPluginCon()->getModule( 'admin_access_restriction' );
458
  try {
459
  $oModule->setNewAccessKeyManually( $sKey )
460
+ ->setSecurityAdminStatusOnOff( true );
461
  $bSuccess = true;
462
  $sMessage = _wpsf__( 'Security Admin setup was successful.' );
463
  }
templates/php/page/login_intent.php CHANGED
@@ -2,7 +2,7 @@
2
  <head>
3
  <link rel="stylesheet" href="<?php echo $hrefs[ 'css_bootstrap' ]; ?>" />
4
  <title><?php echo $strings[ 'page_title' ]; ?></title>
5
- <link rel="icon" type="image/png" href="<?php echo $hrefs[ 'favicon' ]; ?>" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
 
8
  <style>
@@ -78,8 +78,8 @@
78
 
79
  <div class="container-fluid">
80
  <div class="row">
81
- <div class="col-8 offset-2 col-md-6 offset-md-3">
82
- <img id="ShieldLogo" class="img-fluid" src="<?php echo $hrefs[ 'shield_logo' ]; ?>" />
83
  </div>
84
  </div>
85
  <div class="row">
2
  <head>
3
  <link rel="stylesheet" href="<?php echo $hrefs[ 'css_bootstrap' ]; ?>" />
4
  <title><?php echo $strings[ 'page_title' ]; ?></title>
5
+ <link rel="icon" type="image/png" href="<?php echo $imgs[ 'favicon' ]; ?>" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
 
8
  <style>
78
 
79
  <div class="container-fluid">
80
  <div class="row">
81
+ <div class="col-8 offset-2 col-md-6 offset-md-3 text-center">
82
+ <img id="ShieldLogo" class="img-fluid" src="<?php echo $imgs[ 'banner' ]; ?>" />
83
  </div>
84
  </div>
85
  <div class="row">
templates/php/snippets/gasp_js.php CHANGED
@@ -23,7 +23,8 @@
23
  }
24
  </style>
25
 
26
- <p id="<?php echo $sUniqElem; ?>" class="icwpImHuman_<?php echo $sUniqId; ?>"></p>
 
27
 
28
  <script type="text/javascript">
29
 
@@ -36,10 +37,16 @@
36
  bRun<?php echo $sUniqElem; ?> = true;
37
 
38
  var the_p<?php echo $sUniqId; ?> = document.getElementById( "<?php echo $sUniqElem; ?>" );
 
 
 
 
39
 
40
  var hon<?php echo $sUniqId; ?> = document.createElement( "input" );
41
  hon<?php echo $sUniqId; ?>.type = "hidden";
42
  hon<?php echo $sUniqId; ?>.name = "icwp_wpsf_login_email";
 
 
43
  the_p<?php echo $sUniqId; ?>.appendChild( hon<?php echo $sUniqId; ?> );
44
 
45
  { /* Prevent multiple checkboxes within the same form */
23
  }
24
  </style>
25
 
26
+ <p id="<?php echo $sUniqElem; ?>" class="icwpImHuman_<?php echo $sUniqId; ?>">
27
+ <?php echo $strings[ 'loading' ]; ?> ...</p>
28
 
29
  <script type="text/javascript">
30
 
37
  bRun<?php echo $sUniqElem; ?> = true;
38
 
39
  var the_p<?php echo $sUniqId; ?> = document.getElementById( "<?php echo $sUniqElem; ?>" );
40
+ if ( typeof the_p<?php echo $sUniqId; ?> === 'undefined' ) {
41
+ console.log( '[Shield Security] GASP Checkbox: Problem on your page and perhaps Javascript is breaking.' );
42
+ return;
43
+ }
44
 
45
  var hon<?php echo $sUniqId; ?> = document.createElement( "input" );
46
  hon<?php echo $sUniqId; ?>.type = "hidden";
47
  hon<?php echo $sUniqId; ?>.name = "icwp_wpsf_login_email";
48
+
49
+ the_p<?php echo $sUniqId; ?>.innerHTML = '';
50
  the_p<?php echo $sUniqId; ?>.appendChild( hon<?php echo $sUniqId; ?> );
51
 
52
  { /* Prevent multiple checkboxes within the same form */
templates/php/snippets/plugin-deactivate-survey.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="icwpWpsfSurvey" class="hidden icwp-wpsf-dialog">
2
+ <p>Deactivating Shield makes us sad, but you can help us improve by letting us know why.</p>
3
+ <p>This is optional - will you take a second to tell us why you're deactivating Shield?</p>
4
+ <form id="icwpWpsfSurveyForm">
5
+ <ul>
6
+ <?php foreach ( $inputs[ 'checkboxes' ] as $sKey => $sOpt ) : ?>
7
+ <li><label><input name="<?php echo $sKey; ?>" type="checkbox" value="Y">
8
+ <?php echo $sOpt; ?></label></li>
9
+ <?php endforeach; ?>
10
+ </ul>
11
+ <textarea name="reason_comments" style="width: 360px;" rows="3" placeholder="Any other comments?"></textarea>
12
+ </form>
13
+ </div>
templates/php/snippets/user_profile_backupcode.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="shield-options-backupcode" class="shield-user-options-block">
2
+ <h3><?php echo $strings[ 'title' ]; ?>
3
+ <small>(<?php echo $strings[ 'provided_by' ]; ?>)</small>
4
+ </h3>
5
+ <table class="form-table">
6
+ <tbody>
7
+
8
+ <?php if ( $is_my_user_profile ) : ?>
9
+ <tr>
10
+ <th>
11
+ <label>
12
+ <?php echo $strings[ 'label_enter_code' ]; ?>
13
+ </label>
14
+ </th>
15
+ <td>
16
+ <?php if ( !$has_mfa ) : ?>
17
+ <?php echo $strings[ 'not_available' ]; ?>
18
+ <?php else : ?>
19
+ <a href="#" id="IcwpWpsfGenBackupLoginCode"
20
+ class="button button-primary">
21
+ <?php echo $strings[ 'button_gen_code' ]; ?>
22
+ </a>
23
+ <?php if ( $has_validated_profile ) : ?>
24
+ <a href="#" id="IcwpWpsfDelBackupLoginCode"
25
+ class="button">
26
+ <?php echo $strings[ 'button_del_code' ]; ?>
27
+ </a>
28
+ <?php endif; ?>
29
+ <p class="description">
30
+ <?php echo $strings[ 'description_code' ]; ?>
31
+ <br/><strong><?php echo $strings[ 'description_code_ext1' ]; ?></strong>
32
+ <?php if ( $has_validated_profile ) : ?>
33
+ <br /><?php echo $strings[ 'description_code_ext2' ]; ?>
34
+ <?php endif; ?>
35
+ </p>
36
+ <?php endif; ?>
37
+ </td>
38
+ </tr>
39
+ <?php else : ?>
40
+ <td>
41
+ <p class="description"><?php echo $strings[ 'cant_add_other_user' ]; ?></p>
42
+ </td>
43
+ <?php endif; ?>
44
+
45
+ </tbody>
46
+ </table>
47
+ </div>
templates/twig/pages/base.twig CHANGED
@@ -32,7 +32,7 @@
32
  <div class="container-fluid">
33
  {% block body_content_header %}
34
  <div class="row">
35
- <div class="col-4 offset-4 col-xl-3">
36
  <img id="ShieldLogo" class="img-fluid" src="{{ hrefs.plugin_banner }}" />
37
  </div>
38
  </div>
32
  <div class="container-fluid">
33
  {% block body_content_header %}
34
  <div class="row">
35
+ <div class="col-4 offset-4 col-xl-3 text-center">
36
  <img id="ShieldLogo" class="img-fluid" src="{{ hrefs.plugin_banner }}" />
37
  </div>
38
  </div>
templates/twig/wizard/slides/mfa/authemail.twig CHANGED
@@ -29,7 +29,7 @@
29
  ) }}
30
  </div>
31
  {{ slideMacros.formInput_Hidden( 'wizard-step', 'authemail' ) }}
32
- {{ slideMacros.formInput_Submit( 'Send Code' ) }}
33
  </form>
34
 
35
  <script type="text/javascript">
@@ -37,7 +37,12 @@
37
  if ( oResponse.success ) {
38
  var $oForm = jQuery( event.target );
39
  jQuery( '.stage-verificationcode', $oForm ).slideDown();
40
- jQuery( 'button[type=submit]', $oForm ).prop( 'disabled', false );
 
 
 
 
 
41
  }
42
  } );
43
  </script>
29
  ) }}
30
  </div>
31
  {{ slideMacros.formInput_Hidden( 'wizard-step', 'authemail' ) }}
32
+ {{ slideMacros.formInput_Submit( 'Send Code', 'EmailSendCode' ) }}
33
  </form>
34
 
35
  <script type="text/javascript">
37
  if ( oResponse.success ) {
38
  var $oForm = jQuery( event.target );
39
  jQuery( '.stage-verificationcode', $oForm ).slideDown();
40
+ var $oButt = jQuery( 'button[name=EmailSendCode]', $oForm );
41
+ $oButt.prop( 'disabled', false );
42
+ $oButt.prop( 'value', 'Now Click To Verify Your Code' );
43
+ $oButt.html( 'Now Click To Verify Your Code' );
44
+ $oButt.removeClass( 'btn-primary' );
45
+ $oButt.addClass( 'btn-warning' );
46
  }
47
  } );
48
  </script>
templates/twig/wpadmin_pages/insights/index.twig CHANGED
@@ -179,6 +179,9 @@
179
  .mod-audit_trail .mod-icon:before {
180
  content: "\f115";
181
  }
 
 
 
182
  .mod-ips .mod-icon:before {
183
  content: "\f230";
184
  }
@@ -196,7 +199,4 @@
196
  } );
197
  } );
198
  </script>
199
-
200
-
201
-
202
  {% endblock %}
179
  .mod-audit_trail .mod-icon:before {
180
  content: "\f115";
181
  }
182
+ .mod-traffic .mod-icon:before {
183
+ content: "\f177";
184
+ }
185
  .mod-ips .mod-icon:before {
186
  content: "\f230";
187
  }
199
  } );
200
  } );
201
  </script>
 
 
 
202
  {% endblock %}