Shield Security for WordPress - Version 10.1.4

Version Description

Download this release

Release Info

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

Code changes from version 10.1.3 to 10.1.4

Files changed (57) hide show
  1. cl.json +34 -0
  2. icwp-wpsf.php +1 -1
  3. plugin-spec.php +6 -6
  4. readme.txt +2 -2
  5. src/config/feature-audit_trail.php +8 -5
  6. src/config/feature-plugin.php +8 -0
  7. src/lib/src/Controller/Config/ConfigVO.php +79 -0
  8. src/lib/src/Controller/Config/Ops/LoadConfig.php +68 -0
  9. src/lib/src/Controller/Config/Ops/Read.php +43 -0
  10. src/lib/src/Controller/Config/Ops/Save.php +13 -0
  11. src/lib/src/Controller/Controller.php +208 -193
  12. src/lib/src/Controller/Utilities/Upgrade.php +2 -2
  13. src/lib/src/Modules/AuditTrail/Auditors/Users.php +3 -1
  14. src/lib/src/Modules/AuditTrail/Strings.php +4 -1
  15. src/lib/src/Modules/Autoupdates/Insights/OverviewCards.php +1 -1
  16. src/lib/src/Modules/Base/Upgrade.php +2 -2
  17. src/lib/src/Modules/BaseShield/ModCon.php +5 -2
  18. src/lib/src/Modules/CommentsFilter/ModCon.php +1 -1
  19. src/lib/src/Modules/Email/Processor.php +3 -0
  20. src/lib/src/Modules/Events/Strings.php +1 -0
  21. src/lib/src/Modules/Firewall/Processor.php +1 -1
  22. src/lib/src/Modules/IPs/Lib/BlockRequest.php +1 -1
  23. src/lib/src/Modules/Insights/UI.php +1 -1
  24. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php +2 -1
  25. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaSkip.php +5 -5
  26. src/lib/src/Modules/Plugin/AdminNotices.php +70 -20
  27. src/lib/src/Modules/Sessions/Processor.php +2 -0
  28. src/lib/src/Utilities/Consumer/WpLoginCapture.php +24 -2
  29. src/lib/src/Utilities/Github/ListTags.php +22 -0
  30. src/lib/vendor/composer/autoload_classmap.php +20 -16
  31. src/lib/vendor/composer/autoload_psr4.php +1 -1
  32. src/lib/vendor/composer/autoload_static.php +21 -17
  33. src/lib/vendor/fernleafsystems/wordpress-services/src/Core/General.php +5 -0
  34. src/lib/vendor/fernleafsystems/wordpress-services/src/Core/Users.php +101 -136
  35. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Net/IpIdentify.php +10 -5
  36. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/ServiceProviders.php +29 -34
  37. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Feedback.php +3 -3
  38. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matcher.php +7 -7
  39. src/lib/vendor/{mkopinsky/zxcvbn-php/src/Matchers/Match.php → fernleafsystems/zxcvbn-php/src/Matchers/BaseMatch.php} +1 -1
  40. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/Bruteforce.php +2 -2
  41. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/DateMatch.php +2 -2
  42. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/DictionaryMatch.php +2 -2
  43. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/L33tMatch.php +2 -2
  44. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/MatchInterface.php +1 -1
  45. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/RepeatMatch.php +3 -3
  46. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/ReverseDictionaryMatch.php +2 -2
  47. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/SequenceMatch.php +2 -2
  48. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/SpatialMatch.php +2 -2
  49. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/YearMatch.php +2 -2
  50. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/adjacency_graphs.json +0 -0
  51. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/frequency_lists.json +0 -0
  52. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Scorer.php +10 -10
  53. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/TimeEstimator.php +0 -0
  54. src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Zxcvbn.php +0 -0
  55. src/lib/vendor/twig/twig/src/Node/IncludeNode.php +1 -1
  56. src/processors/usermanagement_suspend.php +0 -198
  57. templates/twig/notices/plugin-too-old.twig +8 -0
cl.json CHANGED
@@ -87,6 +87,40 @@
87
  "title": "Bug with MainWP site actions not working in all cases",
88
  "description": [],
89
  "patch": "10.1.3"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
91
  ]
92
  },
87
  "title": "Bug with MainWP site actions not working in all cases",
88
  "description": [],
89
  "patch": "10.1.3"
90
+ },
91
+ {
92
+ "type": "new",
93
+ "title": "Full support for Application Passwords arriving with WordPress 5.6",
94
+ "description": [
95
+ "Part of the purpose of Application Passwords is to allow APIs and 3rd parties to integrate with your WP site.",
96
+ "Shield recognises authentication via Application Passwords and doesn't apply restrictions to it, including 2FA.",
97
+ "Of course, failed logins attempted through Application Passwords will be treated as an offense against the site, as always."
98
+ ],
99
+ "patch": "10.1.4"
100
+ },
101
+ {
102
+ "type": "improved",
103
+ "title": "Full support for PHP 8.0",
104
+ "description": [],
105
+ "patch": "10.1.4"
106
+ },
107
+ {
108
+ "type": "fixed",
109
+ "title": "504 Gateway Timeout error on servers with malconfigured rDNS lookups.",
110
+ "description": [],
111
+ "patch": "10.1.4"
112
+ },
113
+ {
114
+ "type": "fixed",
115
+ "title": "Ensure requests from ManageWP bypass Shield protections, where possible.",
116
+ "description": [],
117
+ "patch": "10.1.4"
118
+ },
119
+ {
120
+ "type": "new",
121
+ "title": "Add a new WordPress admin notice for when the Shield plugin version gets too old.",
122
+ "description": [],
123
+ "patch": "10.1.4"
124
  }
125
  ]
126
  },
icwp-wpsf.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Shield Security
4
  * Plugin URI: https://shsec.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
- * Version: 10.1.3
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
3
  * Plugin Name: Shield Security
4
  * Plugin URI: https://shsec.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
+ * Version: 10.1.4
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
plugin-spec.php CHANGED
@@ -1,11 +1,11 @@
1
  {
2
  "properties": {
3
- "version": "10.1.3",
4
- "release_timestamp": 1605692545,
5
- "build": "202011.1801",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
- "human_name": "Shield",
9
  "menu_title": "Shield",
10
  "text_domain": "wp-simple-firewall",
11
  "base_permissions": "manage_options",
@@ -19,7 +19,7 @@
19
  "enable_premium": true
20
  },
21
  "requirements": {
22
- "php": "5.4.0",
23
  "wordpress": "3.5.2"
24
  },
25
  "upgrade_reqs": {
@@ -86,7 +86,7 @@
86
  "has_submenu": true
87
  },
88
  "labels": {
89
- "Name": "Shield",
90
  "Description": "Ultimate WP Security Protection - Scans, 2FA, Firewall, SPAM, Audit Trail, Security Admin, and so much more.",
91
  "Title": "Shield Security",
92
  "Author": "Shield Security",
1
  {
2
  "properties": {
3
+ "version": "10.1.4",
4
+ "release_timestamp": 1607337143,
5
+ "build": "202012.0701",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
+ "human_name": "Shield Security",
9
  "menu_title": "Shield",
10
  "text_domain": "wp-simple-firewall",
11
  "base_permissions": "manage_options",
19
  "enable_premium": true
20
  },
21
  "requirements": {
22
+ "php": "7.0.0",
23
  "wordpress": "3.5.2"
24
  },
25
  "upgrade_reqs": {
86
  "has_submenu": true
87
  },
88
  "labels": {
89
+ "Name": "Shield Security",
90
  "Description": "Ultimate WP Security Protection - Scans, 2FA, Firewall, SPAM, Audit Trail, Security Admin, and so much more.",
91
  "Title": "Shield Security",
92
  "Author": "Shield Security",
readme.txt CHANGED
@@ -7,8 +7,8 @@ Tags: scan, malware, firewall, two factor authentication, login protection
7
  Requires at least: 3.5.2
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
- Tested up to: 5.5
11
- Stable tag: 10.1.3
12
 
13
  The highest rated WordPress Security plugin, delivering unparalleled, all-in-one protection for you and your customers.
14
 
7
  Requires at least: 3.5.2
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
+ Tested up to: 5.6
11
+ Stable tag: 10.1.4
12
 
13
  The highest rated WordPress Security plugin, delivering unparalleled, all-in-one protection for you and your customers.
14
 
src/config/feature-audit_trail.php CHANGED
@@ -1,6 +1,6 @@
1
  {
2
- "slug": "audit_trail",
3
- "properties": {
4
  "slug": "audit_trail",
5
  "name": "Audit Trail",
6
  "sidebar_name": "Audit Trail",
@@ -32,7 +32,7 @@
32
  }
33
  }
34
  ],
35
- "sections": [
36
  {
37
  "slug": "section_audit_trail_options",
38
  "primary": true,
@@ -67,7 +67,7 @@
67
  "hidden": true
68
  }
69
  ],
70
- "options": [
71
  {
72
  "key": "enable_audit_trail",
73
  "section": "section_enable_plugin_feature_audit_trail",
@@ -162,7 +162,7 @@
162
  "default": 0
163
  }
164
  ],
165
- "definitions": {
166
  "db_classes": {
167
  "audit": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AuditTrail\\Handler"
168
  },
@@ -248,6 +248,9 @@
248
  "user_login": {
249
  "context": "users"
250
  },
 
 
 
251
  "user_registered": {
252
  "context": "users"
253
  },
1
  {
2
+ "slug": "audit_trail",
3
+ "properties": {
4
  "slug": "audit_trail",
5
  "name": "Audit Trail",
6
  "sidebar_name": "Audit Trail",
32
  }
33
  }
34
  ],
35
+ "sections": [
36
  {
37
  "slug": "section_audit_trail_options",
38
  "primary": true,
67
  "hidden": true
68
  }
69
  ],
70
+ "options": [
71
  {
72
  "key": "enable_audit_trail",
73
  "section": "section_enable_plugin_feature_audit_trail",
162
  "default": 0
163
  }
164
  ],
165
+ "definitions": {
166
  "db_classes": {
167
  "audit": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AuditTrail\\Handler"
168
  },
248
  "user_login": {
249
  "context": "users"
250
  },
251
+ "user_login_app": {
252
+ "context": "users"
253
+ },
254
  "user_registered": {
255
  "context": "users"
256
  },
src/config/feature-plugin.php CHANGED
@@ -18,6 +18,14 @@
18
  "order": 10
19
  },
20
  "admin_notices": {
 
 
 
 
 
 
 
 
21
  "override-forceoff": {
22
  "id": "override-forceoff",
23
  "schedule": "conditions",
18
  "order": 10
19
  },
20
  "admin_notices": {
21
+ "plugin-too-old": {
22
+ "id": "plugin-too-old",
23
+ "schedule": "conditions",
24
+ "valid_admin": true,
25
+ "plugin_page_only": false,
26
+ "can_dismiss": true,
27
+ "type": "error"
28
+ },
29
  "override-forceoff": {
30
  "id": "override-forceoff",
31
  "schedule": "conditions",
src/lib/src/Controller/Config/ConfigVO.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Controller\Config;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
6
+
7
+ /**
8
+ * Class ConfigVO
9
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Controller\Config
10
+ * @property array $properties
11
+ * @property array $requirements
12
+ * @property array $paths
13
+ * @property array $includes
14
+ * @property array $menu
15
+ * @property array $labels
16
+ * @property array $action_links
17
+ * @property array $meta
18
+ * @property array $plugin_meta
19
+ * @property array $upgrade_reqs
20
+ * @property array $version_upgrades
21
+ * -- not part of config file --
22
+ * @property string $hash
23
+ * @property string $previous_version
24
+ * @property array $update_first_detected
25
+ */
26
+ class ConfigVO {
27
+
28
+ use StdClassAdapter {
29
+ __get as __adapterGet;
30
+ }
31
+
32
+ /**
33
+ * @var bool
34
+ */
35
+ public $rebuilt = false;
36
+
37
+ /**
38
+ * @param string $key
39
+ * @return mixed
40
+ */
41
+ public function __get( $key ) {
42
+ $val = $this->__adapterGet( $key );
43
+
44
+ switch ( $key ) {
45
+
46
+ case 'menu':
47
+ $val = array_merge(
48
+ [
49
+ 'show' => true,
50
+ 'top_level' => true,
51
+ 'do_submenu_fix' => true,
52
+ 'has_submenu' => true,
53
+ 'title' => 'undefined menu title',
54
+ 'callback' => 'undefinedMenuCallback',
55
+ 'icon_image' => 'pluginlogo_16x16.png',
56
+ ],
57
+ is_array( $val ) ? $val : []
58
+ );
59
+ break;
60
+
61
+ case 'previous_version':
62
+ if ( empty( $val ) ) {
63
+ $val = $this->properties[ 'version' ];
64
+ }
65
+ break;
66
+
67
+ case 'update_first_detected':
68
+ if ( empty( $val ) ) {
69
+ $val = [];
70
+ }
71
+ break;
72
+
73
+ default:
74
+ break;
75
+ }
76
+
77
+ return $val;
78
+ }
79
+ }
src/lib/src/Controller/Config/Ops/LoadConfig.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Controller\Config\Ops;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Controller\Config\ConfigVO;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
9
+
10
+ class LoadConfig {
11
+
12
+ use PluginControllerConsumer;
13
+
14
+ /**
15
+ * @var string
16
+ */
17
+ private $path;
18
+
19
+ /**
20
+ * @var string
21
+ */
22
+ private $store_key;
23
+
24
+ public function __construct( string $path, string $storeKey ) {
25
+ $this->path = $path;
26
+ $this->store_key = $storeKey;
27
+ }
28
+
29
+ /**
30
+ * @return ConfigVO
31
+ * @throws \Exception
32
+ */
33
+ public function run() :ConfigVO {
34
+ $def = $this->fromWp();
35
+ $rebuild = empty( $def ) || !is_array( $def );
36
+
37
+ $specHash = sha1_file( $this->path );
38
+ if ( !$rebuild ) {
39
+ $con = $this->getCon();
40
+ $version = $def[ 'properties' ][ 'version' ] ?? '0';
41
+
42
+ $rebuild = empty( $def[ 'hash' ] ) || !hash_equals( $def[ 'hash' ], $specHash )
43
+ || ( $version !== Services::WpPlugins()->getPluginAsVo( $con->getPluginBaseFile() )->Version );
44
+ $def[ 'hash' ] = $specHash;
45
+ }
46
+
47
+ $cfg = ( new ConfigVO() )->applyFromArray( $rebuild ? $this->fromFile() : $def );
48
+ $cfg->hash = $specHash;
49
+ $cfg->rebuilt = $rebuild;
50
+
51
+ return $cfg;
52
+ }
53
+
54
+ /**
55
+ * @return array
56
+ * @throws \Exception
57
+ */
58
+ public function fromFile() :array {
59
+ return Read::FromFile( $this->path );
60
+ }
61
+
62
+ /**
63
+ * @return array|null
64
+ */
65
+ public function fromWp() {
66
+ return Transient::Get( $this->store_key );
67
+ }
68
+ }
src/lib/src/Controller/Config/Ops/Read.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Controller\Config\Ops;
4
+
5
+ use FernleafSystems\Wordpress\Services\Services;
6
+
7
+ class Read {
8
+
9
+ /**
10
+ * @param string $path
11
+ * @return array
12
+ * @throws \Exception
13
+ */
14
+ public static function FromFile( string $path ) :array {
15
+ $FS = Services::WpFs();
16
+ foreach ( [ 'json', 'php' ] as $sExt ) {
17
+ $cfgFile = Services::Data()->addExtensionToFilePath( $path, $sExt );
18
+ if ( $FS->isFile( $cfgFile ) ) {
19
+ return self::FromString( $FS->getFileContentUsingInclude( $cfgFile ) );
20
+ }
21
+ }
22
+ throw new \LogicException( 'No config file present for slug: '.basename( $path ) );
23
+ }
24
+
25
+ /**
26
+ * @param string $def
27
+ * @return array
28
+ * @throws \Exception
29
+ */
30
+ public static function FromString( string $def ) :array {
31
+ $spec = [];
32
+ $def = trim( $def );
33
+
34
+ if ( !empty( $def ) ) {
35
+ $spec = json_decode( $def, true );
36
+ }
37
+ if ( empty( $spec ) || !is_array( $spec ) ) {
38
+ throw new \Exception( 'Could not parse the definition file.' );
39
+ }
40
+
41
+ return $spec;
42
+ }
43
+ }
src/lib/src/Controller/Config/Ops/Save.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Controller\Config\Ops;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Controller\Config\ConfigVO;
6
+ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
7
+
8
+ class Save {
9
+
10
+ public static function ToWp( ConfigVO $cfg, string $key ) :bool {
11
+ return Transient::Set( $key, $cfg->getRawDataAsArray() );
12
+ }
13
+ }
src/lib/src/Controller/Controller.php CHANGED
@@ -5,10 +5,12 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Controller;
5
  use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
6
  use FernleafSystems\Wordpress\Plugin\Shield;
7
  use FernleafSystems\Wordpress\Services\Services;
 
8
 
9
  /**
10
  * Class Controller
11
  * @package FernleafSystems\Wordpress\Plugin\Shield\Controller
 
12
  * @property bool $is_activating
13
  * @property bool $is_debug
14
  * @property bool $modules_loaded
@@ -46,11 +48,6 @@ class Controller {
46
  */
47
  private $sRootFile;
48
 
49
- /**
50
- * @var bool
51
- */
52
- protected $bRebuildOptions;
53
-
54
  /**
55
  * @var string
56
  * @deprecated 10.1
@@ -72,18 +69,13 @@ class Controller {
72
  */
73
  protected static $sRequestId;
74
 
75
- /**
76
- * @var bool
77
- */
78
- private $bMeetsBasePermissions;
79
-
80
  /**
81
  * @var string
82
  */
83
  protected $sAdminNoticeError = '';
84
 
85
  /**
86
- * @var \ICWP_WPSF_FeatureHandler_Base[]
87
  */
88
  protected $aModules;
89
 
@@ -152,6 +144,8 @@ class Controller {
152
  $this->modules = [];
153
 
154
  $this->loadServices();
 
 
155
  $this->checkMinimumRequirements();
156
  $this->doRegisterHooks();
157
 
@@ -169,6 +163,12 @@ class Controller {
169
 
170
  switch ( $key ) {
171
 
 
 
 
 
 
 
172
  case 'is_debug':
173
  if ( is_null( $val ) ) {
174
  $val = ( new Shield\Controller\Utilities\DebugMode() )
@@ -195,6 +195,7 @@ class Controller {
195
  /**
196
  * @return array
197
  * @throws \Exception
 
198
  */
199
  private function readPluginSpecification() :array {
200
  $spec = [];
@@ -220,19 +221,19 @@ class Controller {
220
  $bMeetsRequirements = true;
221
  $aRequirementsMessages = $this->getRequirementsMessages();
222
 
223
- $sMinimumPhp = $this->getPluginSpec_Requirement( 'php' );
224
- if ( !empty( $sMinimumPhp ) ) {
225
- if ( version_compare( Services::Data()->getPhpVersion(), $sMinimumPhp, '<' ) ) {
226
- $aRequirementsMessages[] = sprintf( 'PHP does not meet minimum version. Your version: %s. Required Version: %s.', PHP_VERSION, $sMinimumPhp );
227
  $bMeetsRequirements = false;
228
  }
229
  }
230
 
231
- $sMinimumWp = $this->getPluginSpec_Requirement( 'wordpress' );
232
- if ( !empty( $sMinimumWp ) ) {
233
  $sWpVersion = Services::WpGeneral()->getVersion( true );
234
- if ( version_compare( $sWpVersion, $sMinimumWp, '<' ) ) {
235
- $aRequirementsMessages[] = sprintf( 'WordPress does not meet minimum version. Your version: %s. Required Version: %s.', $sWpVersion, $sMinimumWp );
236
  $bMeetsRequirements = false;
237
  }
238
  }
@@ -513,8 +514,7 @@ class Controller {
513
  */
514
  public function onWpAdminBarMenu( $oAdminBar ) {
515
  $bShow = apply_filters( $this->prefix( 'show_admin_bar_menu' ),
516
- $this->isValidAdminArea( true )
517
- && (bool)$this->getPluginSpec_Property( 'show_admin_bar_menu' )
518
  );
519
  if ( $bShow ) {
520
  $aMenuItems = apply_filters( $this->prefix( 'admin_bar_menu_items' ), [] );
@@ -540,7 +540,7 @@ class Controller {
540
 
541
  public function onWpDashboardSetup() {
542
  $show = apply_filters( $this->prefix( 'show_dashboard_widget' ),
543
- $this->isValidAdminArea() && (bool)$this->getPluginSpec_Property( 'show_dashboard_widget' )
544
  );
545
  if ( $show ) {
546
  wp_add_dashboard_widget(
@@ -612,22 +612,22 @@ class Controller {
612
  * @return bool
613
  */
614
  protected function createPluginMenu() {
 
615
 
616
- $bHideMenu = apply_filters( $this->prefix( 'filter_hidePluginMenu' ), !$this->getPluginSpec_Menu( 'show' ) );
617
- if ( $bHideMenu ) {
618
  return true;
619
  }
620
 
621
- if ( $this->getPluginSpec_Menu( 'top_level' ) ) {
622
 
623
- $aLabels = $this->getLabels();
624
- $sMenuTitle = empty( $aLabels[ 'MenuTitle' ] ) ? $this->getPluginSpec_Menu( 'title' ) : $aLabels[ 'MenuTitle' ];
625
  if ( is_null( $sMenuTitle ) ) {
626
  $sMenuTitle = $this->getHumanName();
627
  }
628
 
629
- $sMenuIcon = $this->getPluginUrl_Image( $this->getPluginSpec_Menu( 'icon_image' ) );
630
- $sIconUrl = empty( $aLabels[ 'icon_url_16x16' ] ) ? $sMenuIcon : $aLabels[ 'icon_url_16x16' ];
631
 
632
  $sFullParentMenuId = $this->getPluginPrefix();
633
  add_menu_page(
@@ -635,15 +635,15 @@ class Controller {
635
  $sMenuTitle,
636
  $this->getBasePermissions(),
637
  $sFullParentMenuId,
638
- [ $this, $this->getPluginSpec_Menu( 'callback' ) ],
639
  $sIconUrl
640
  );
641
 
642
- if ( $this->getPluginSpec_Menu( 'has_submenu' ) ) {
643
 
644
- $aPluginMenuItems = apply_filters( $this->prefix( 'submenu_items' ), [] );
645
- if ( !empty( $aPluginMenuItems ) ) {
646
- foreach ( $aPluginMenuItems as $sMenuTitle => $aMenu ) {
647
  list( $sMenuItemText, $sMenuItemId, $aMenuCallBack, $bShowItem ) = $aMenu;
648
  add_submenu_page(
649
  $bShowItem ? $sFullParentMenuId : null,
@@ -657,7 +657,7 @@ class Controller {
657
  }
658
  }
659
 
660
- if ( $this->getPluginSpec_Menu( 'do_submenu_fix' ) ) {
661
  $this->fixSubmenu();
662
  }
663
  }
@@ -688,7 +688,7 @@ class Controller {
688
 
689
  if ( $sPluginFile == $this->getPluginBaseFile() ) {
690
  $sTemplate = '<strong><a href="%s" target="_blank">%s</a></strong>';
691
- foreach ( $this->getPluginSpec_PluginMeta() as $aHref ) {
692
  array_push( $aPluginMeta, sprintf( $sTemplate, $aHref[ 'href' ], $aHref[ 'name' ] ) );
693
  }
694
  }
@@ -707,13 +707,13 @@ class Controller {
707
  unset( $aActionLinks[ 'edit' ] );
708
  }
709
 
710
- $aLinksToAdd = $this->getPluginSpec_ActionLinks( 'add' );
711
- if ( is_array( $aLinksToAdd ) ) {
712
 
713
  $bPro = $this->isPremiumActive();
714
  $oDP = Services::Data();
715
  $sLinkTemplate = '<a href="%s" target="%s" title="%s">%s</a>';
716
- foreach ( $aLinksToAdd as $aLink ) {
717
  $aLink = array_merge(
718
  [
719
  'highlight' => false,
@@ -755,11 +755,11 @@ class Controller {
755
  }
756
 
757
  public function onWpEnqueueFrontendCss() {
758
- $aFrontendIncludes = $this->getPluginSpec_Include( 'frontend' );
759
- if ( isset( $aFrontendIncludes[ 'css' ] ) && !empty( $aFrontendIncludes[ 'css' ] ) && is_array( $aFrontendIncludes[ 'css' ] ) ) {
760
 
761
  $aDeps = [];
762
- foreach ( $aFrontendIncludes[ 'css' ] as $sAsset ) {
763
  $sUrl = $this->getPluginUrl_Css( $sAsset );
764
  if ( !empty( $sUrl ) ) {
765
  $sAsset = $this->prefix( $sAsset );
@@ -775,39 +775,37 @@ class Controller {
775
 
776
  $aIncludes = [];
777
  if ( $this->getIsPage_PluginAdmin() ) {
778
- $aAdminIncludes = $this->getPluginSpec_Include( 'plugin_admin' );
779
- if ( !empty( $aAdminIncludes[ 'js' ] ) && is_array( $aAdminIncludes[ 'js' ] ) ) {
780
- $aIncludes = $aAdminIncludes[ 'js' ];
781
  }
782
  }
783
  elseif ( $this->isValidAdminArea() ) {
784
- $aAdminIncludes = $this->getPluginSpec_Include( 'admin' );
785
- if ( !empty( $aAdminIncludes[ 'js' ] ) && is_array( $aAdminIncludes[ 'js' ] ) ) {
786
- $aIncludes = $aAdminIncludes[ 'js' ];
787
  }
788
  }
789
 
790
- $aBuiltIn = [
791
- 'jquery'
792
- ];
793
 
794
  $aDeps = [];
795
- foreach ( $aIncludes as $sAsset ) {
796
 
797
  // Built-in handles
798
- if ( in_array( $sAsset, $aBuiltIn ) ) {
799
- if ( wp_script_is( $sAsset, 'registered' ) ) {
800
- wp_enqueue_script( $sAsset );
801
- $aDeps[] = $sAsset;
802
  }
803
  }
804
  else {
805
- $sUrl = $this->getPluginUrl_Js( $sAsset );
806
  if ( !empty( $sUrl ) ) {
807
- $sAsset = $this->prefix( $sAsset );
808
- wp_register_script( $sAsset, $sUrl, $aDeps, $this->getVersion() );
809
- wp_enqueue_script( $sAsset );
810
- $aDeps[] = $sAsset;
811
  }
812
  }
813
  }
@@ -817,26 +815,26 @@ class Controller {
817
 
818
  $aIncludes = [];
819
  if ( $this->getIsPage_PluginAdmin() ) {
820
- $aAdminIncludes = $this->getPluginSpec_Include( 'plugin_admin' );
821
- if ( !empty( $aAdminIncludes[ 'css' ] ) && is_array( $aAdminIncludes[ 'css' ] ) ) {
822
- $aIncludes = $aAdminIncludes[ 'css' ];
823
  }
824
  }
825
  elseif ( $this->isValidAdminArea() ) {
826
- $aAdminIncludes = $this->getPluginSpec_Include( 'admin' );
827
- if ( !empty( $aAdminIncludes[ 'css' ] ) && is_array( $aAdminIncludes[ 'css' ] ) ) {
828
- $aIncludes = $aAdminIncludes[ 'css' ];
829
  }
830
  }
831
 
832
  $aDeps = [];
833
- foreach ( $aIncludes as $sAsset ) {
834
- $sUrl = $this->getPluginUrl_Css( $sAsset );
835
  if ( !empty( $sUrl ) ) {
836
- $sAsset = $this->prefix( $sAsset );
837
- wp_register_style( $sAsset, $sUrl, $aDeps, $this->getVersion() );
838
- wp_enqueue_style( $sAsset );
839
- $aDeps[] = $sAsset;
840
  }
841
  }
842
  }
@@ -888,72 +886,70 @@ class Controller {
888
  /**
889
  * This will hook into the saving of plugin update information and if there is an update for this plugin, it'll add
890
  * a data stamp to state when the update was first detected.
891
- * @param \stdClass $updateData
892
  * @return \stdClass
893
  */
894
- public function setUpdateFirstDetectedAt( $updateData ) {
895
 
896
- if ( !empty( $updateData ) && !empty( $updateData->response )
897
- && isset( $updateData->response[ $this->getPluginBaseFile() ] ) ) {
898
- // i.e. there's an update available
899
 
900
  $new = Services::WpPlugins()->getUpdateNewVersion( $this->getPluginBaseFile() );
901
- if ( !empty( $new ) ) {
902
- $opts = $this->getPluginControllerOptions();
903
- if ( !isset( $opts->update_first_detected ) || ( count( $opts->update_first_detected ) > 3 ) ) {
904
- $opts->update_first_detected = [];
905
  }
906
- if ( !isset( $opts->update_first_detected[ $new ] ) ) {
907
- $opts->update_first_detected[ $new ] = Services::Request()->ts();
908
  }
 
909
  }
910
  }
911
 
912
- return $updateData;
913
  }
914
 
915
  /**
916
  * This is a filter method designed to say whether WordPress plugin upgrades should be permitted,
917
  * based on the plugin settings.
918
- * @param bool $bDoAutoUpdate
919
  * @param string|object $mItem
920
  * @return bool
921
  */
922
- public function onWpAutoUpdate( $bDoAutoUpdate, $mItem ) {
923
- $oWp = Services::WpGeneral();
924
  $oWpPlugins = Services::WpPlugins();
925
 
926
- $sFile = $oWp->getFileFromAutomaticUpdateItem( $mItem );
927
 
928
  // The item in question is this plugin...
929
  if ( $sFile === $this->getPluginBaseFile() ) {
930
- $sAutoupdateSpec = $this->getPluginSpec_Property( 'autoupdate' );
931
 
932
- $oConOptions = $this->getPluginControllerOptions();
933
-
934
- if ( !$oWp->isRunningAutomaticUpdates() && $sAutoupdateSpec == 'confidence' ) {
935
- $sAutoupdateSpec = 'yes'; // so that we appear to be automatically updating
936
  }
937
 
938
- $sNewVersion = $oWpPlugins->getUpdateNewVersion( $sFile );
939
 
940
- switch ( $sAutoupdateSpec ) {
941
 
942
  case 'yes' :
943
- $bDoAutoUpdate = true;
944
  break;
945
 
946
  case 'block' :
947
- $bDoAutoUpdate = false;
948
  break;
949
 
950
  case 'confidence' :
951
- $bDoAutoUpdate = false;
952
- $nAutoupdateDays = $this->getPluginSpec_Property( 'autoupdate_days' );
953
- if ( !empty( $sNewVersion ) ) {
954
- $nFirstDetected = isset( $oConOptions->update_first_detected[ $sNewVersion ] ) ? $oConOptions->update_first_detected[ $sNewVersion ] : 0;
955
- $nTimeUpdateAvailable = Services::Request()->ts() - $nFirstDetected;
956
- $bDoAutoUpdate = ( $nFirstDetected > 0 && ( $nTimeUpdateAvailable > DAY_IN_SECONDS*$nAutoupdateDays ) );
957
  }
958
  break;
959
 
@@ -962,7 +958,7 @@ class Controller {
962
  break;
963
  }
964
  }
965
- return $bDoAutoUpdate;
966
  }
967
 
968
  /**
@@ -988,7 +984,10 @@ class Controller {
988
 
989
  public function getLabels() :array {
990
 
991
- $labels = array_map( 'stripslashes', apply_filters( $this->prefix( 'plugin_labels' ), $this->getPluginSpec_Labels() ) );
 
 
 
992
 
993
  $oDP = Services::Data();
994
  foreach ( [ '16x16', '32x32', '128x128' ] as $dimension ) {
@@ -1028,21 +1027,14 @@ class Controller {
1028
  /**
1029
  * Added to a WordPress filter ('all_plugins') which will remove this particular plugin from the
1030
  * list of all plugins based on the "plugin file" name.
1031
- * @param array $aPlugins
1032
  * @return array
1033
  */
1034
- public function filter_hidePluginFromTableList( $aPlugins ) {
1035
-
1036
- $bHide = apply_filters( $this->prefix( 'hide_plugin' ), false );
1037
- if ( !$bHide ) {
1038
- return $aPlugins;
1039
- }
1040
-
1041
- $sPluginBaseFileName = $this->getPluginBaseFile();
1042
- if ( isset( $aPlugins[ $sPluginBaseFileName ] ) ) {
1043
- unset( $aPlugins[ $sPluginBaseFileName ] );
1044
  }
1045
- return $aPlugins;
1046
  }
1047
 
1048
  /**
@@ -1050,50 +1042,63 @@ class Controller {
1050
  * from the WordPress Admin UI.
1051
  * In order to ensure that WordPress still checks for plugin updates it will not remove this plugin from
1052
  * the list of plugins if DOING_CRON is set to true.
1053
- * @param \stdClass $oPlugins
1054
  * @return \stdClass
1055
- * @uses $this->fHeadless if the plugin is headless, it is hidden
1056
  */
1057
- public function filter_hidePluginUpdatesFromUI( $oPlugins ) {
1058
-
1059
- if ( Services::WpGeneral()->isCron() ) {
1060
- return $oPlugins;
1061
  }
1062
- if ( !apply_filters( $this->prefix( 'hide_plugin_updates' ), false ) ) {
1063
- return $oPlugins;
1064
- }
1065
- if ( isset( $oPlugins->response[ $this->getPluginBaseFile() ] ) ) {
1066
- unset( $oPlugins->response[ $this->getPluginBaseFile() ] );
1067
- }
1068
- return $oPlugins;
1069
  }
1070
 
1071
  /**
1072
- * @param string $sSuffix
1073
- * @param string $sGlue
1074
  * @return string
1075
  */
1076
- public function prefix( $sSuffix = '', $sGlue = '-' ) {
1077
- $sPrefix = $this->getPluginPrefix( $sGlue );
1078
 
1079
- if ( $sSuffix == $sPrefix || strpos( $sSuffix, $sPrefix.$sGlue ) === 0 ) { //it already has the full prefix
1080
- return $sSuffix;
1081
  }
1082
 
1083
- return sprintf( '%s%s%s', $sPrefix, empty( $sSuffix ) ? '' : $sGlue, empty( $sSuffix ) ? '' : $sSuffix );
1084
  }
1085
 
1086
  public function prefixOption( string $suffix = '' ) :string {
1087
  return $this->prefix( $suffix, '_' );
1088
  }
1089
 
 
 
 
 
 
 
 
 
 
 
 
 
1090
  /**
1091
  * @return array
 
1092
  */
1093
  public function getPluginSpec() {
 
 
 
1094
  return $this->getPluginControllerOptions()->plugin_spec;
1095
  }
1096
 
 
 
 
 
 
1097
  protected function getPluginSpec_ActionLinks( string $key ) :array {
1098
  $aData = $this->getPluginSpec()[ 'action_links' ];
1099
  return $aData[ $key ] ?? [];
@@ -1102,6 +1107,7 @@ class Controller {
1102
  /**
1103
  * @param string $key
1104
  * @return mixed|null
 
1105
  */
1106
  protected function getPluginSpec_Include( string $key ) {
1107
  $aData = $this->getPluginSpec()[ 'includes' ];
@@ -1111,6 +1117,7 @@ class Controller {
1111
  /**
1112
  * @param string $key
1113
  * @return array|string
 
1114
  */
1115
  protected function getPluginSpec_Labels( string $key = '' ) {
1116
  $oSpec = $this->getPluginSpec();
@@ -1126,6 +1133,7 @@ class Controller {
1126
  /**
1127
  * @param string $key
1128
  * @return mixed|null
 
1129
  */
1130
  protected function getPluginSpec_Menu( string $key ) {
1131
  $aData = $this->getPluginSpec()[ 'menu' ];
@@ -1137,6 +1145,9 @@ class Controller {
1137
  * @return string|null
1138
  */
1139
  public function getPluginSpec_Path( string $key ) {
 
 
 
1140
  $aData = $this->getPluginSpec()[ 'paths' ];
1141
  return $aData[ $key ] ?? null;
1142
  }
@@ -1145,13 +1156,26 @@ class Controller {
1145
  * @param string $key
1146
  * @return mixed|null
1147
  */
 
 
 
 
 
 
 
 
 
1148
  protected function getPluginSpec_Property( string $key ) {
 
 
 
1149
  $data = $this->getPluginSpec()[ 'properties' ];
1150
  return $data[ $key ] ?? null;
1151
  }
1152
 
1153
  /**
1154
  * @return array
 
1155
  */
1156
  protected function getPluginSpec_PluginMeta() {
1157
  $aSpec = $this->getPluginSpec();
@@ -1161,6 +1185,7 @@ class Controller {
1161
  /**
1162
  * @param string $key
1163
  * @return mixed|null
 
1164
  */
1165
  protected function getPluginSpec_Requirement( string $key ) {
1166
  $aData = $this->getPluginSpec()[ 'requirements' ];
@@ -1168,6 +1193,9 @@ class Controller {
1168
  }
1169
 
1170
  public function getBasePermissions() :string {
 
 
 
1171
  return $this->getPluginSpec_Property( 'base_permissions' );
1172
  }
1173
 
@@ -1206,9 +1234,8 @@ class Controller {
1206
  * current_user_can() never gets caught up in an infinite loop of permissions checking
1207
  */
1208
  public function getMeetsBasePermissions() :bool {
1209
- if ( did_action( 'init' ) && !isset( $this->bMeetsBasePermissions ) ) {
1210
  $this->user_can_base_permissions = current_user_can( $this->getBasePermissions() );
1211
- $this->bMeetsBasePermissions = $this->user_can_base_permissions;
1212
  }
1213
  return (bool)$this->user_can_base_permissions;
1214
  }
@@ -1248,25 +1275,11 @@ class Controller {
1248
  return Services::WpGeneral()->getCurrentWpAdminPage() === $this->getPluginPrefix();
1249
  }
1250
 
 
 
 
 
1251
  public function getIsRebuildOptionsFromFile() :bool {
1252
- if ( isset( $this->rebuild_options ) ) {
1253
- return $this->rebuild_options;
1254
- }
1255
-
1256
- // The first choice is to look for the file hash. If it's "always" empty, it means we could never
1257
- // hash the file in the first place so it's not ever effectively used and it falls back to the rebuild file
1258
- $opts = $this->getPluginControllerOptions();
1259
- $specPath = $this->getPathPluginSpec();
1260
- $specHash = @sha1_file( $specPath );
1261
- $specModTS = Services::WpFs()->getModifiedTime( $specPath );
1262
-
1263
- $this->rebuild_options =
1264
- ( $this->getVersion() !== Services::WpPlugins()->getPluginAsVo( $this->getPluginBaseFile() )->Version )
1265
- || ( empty( $opts->hash ) || !hash_equals( $opts->hash, $specHash ) )
1266
- || ( empty( $opts->mod_time || $opts->mod_time < $specModTS ) );
1267
-
1268
- $opts->hash = $specHash;
1269
- $opts->mod_time = $specModTS;
1270
  return $this->rebuild_options;
1271
  }
1272
 
@@ -1445,6 +1458,10 @@ class Controller {
1445
  return $this->getPluginSpec_Property( 'version' );
1446
  }
1447
 
 
 
 
 
1448
  public function getPreviousVersion() :string {
1449
  $opts = $this->getPluginControllerOptions();
1450
  if ( empty( $opts->previous_version ) ) {
@@ -1467,17 +1484,6 @@ class Controller {
1467
  * @return \stdClass
1468
  */
1469
  public function getPluginControllerOptions() {
1470
- if ( !isset( self::$oControllerOptions ) ) {
1471
-
1472
- self::$oControllerOptions = Services::WpGeneral()->getOption( $this->getPluginControllerOptionsKey() );
1473
- if ( !is_object( self::$oControllerOptions ) ) {
1474
- self::$oControllerOptions = new \stdClass();
1475
- }
1476
-
1477
- if ( $this->getIsRebuildOptionsFromFile() ) {
1478
- self::$oControllerOptions->plugin_spec = $this->readPluginSpecification();
1479
- }
1480
- }
1481
  return self::$oControllerOptions;
1482
  }
1483
 
@@ -1515,10 +1521,15 @@ class Controller {
1515
  protected function saveCurrentPluginControllerOptions() {
1516
  $WP = Services::WpGeneral();
1517
  add_filter( $this->prefix( 'bypass_is_plugin_admin' ), '__return_true' );
 
1518
  if ( $this->plugin_deleting ) {
1519
- $WP->deleteOption( $this->getPluginControllerOptionsKey() );
 
 
 
1520
  }
1521
  else {
 
1522
  $WP->updateOption(
1523
  $this->getPluginControllerOptionsKey(),
1524
  $this->getPluginControllerOptions()
@@ -1537,8 +1548,13 @@ class Controller {
1537
  return $this;
1538
  }
1539
 
 
 
 
 
1540
  /**
1541
  * @return string
 
1542
  */
1543
  private function getPluginControllerOptionsKey() {
1544
  return strtolower( get_class() );
@@ -1938,34 +1954,33 @@ class Controller {
1938
  private function buildPrivacyPolicyContent() {
1939
  try {
1940
  if ( $this->getModule_SecAdmin()->isWlEnabled() ) {
1941
- $sName = $this->getHumanName();
1942
- $sHref = $this->getLabels()[ 'PluginURI' ];
1943
  }
1944
  else {
1945
- $sName = $this->getPluginSpec_Menu( 'title' );
1946
- $sHref = $this->getPluginSpec()[ 'meta' ][ 'privacy_policy_href' ];
1947
  }
1948
 
1949
  /** @var Shield\Modules\AuditTrail\Options $oOpts */
1950
- $oOpts = $this->getModule_AuditTrail()
1951
- ->getOptions();
1952
-
1953
- $sContent = $this->getRenderer()
1954
- ->setTemplate( 'snippets/privacy_policy' )
1955
- ->setTemplateEngineTwig()
1956
- ->setRenderVars(
1957
- [
1958
- 'name' => $sName,
1959
- 'href' => $sHref,
1960
- 'audit_trail_days' => $oOpts->getAutoCleanDays()
1961
- ]
1962
- )
1963
- ->render();
1964
- }
1965
- catch ( \Exception $oE ) {
1966
- $sContent = '';
1967
- }
1968
- return empty( $sContent ) ? '' : wp_kses_post( wpautop( $sContent, false ) );
1969
  }
1970
 
1971
  private function runTests() {
5
  use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
6
  use FernleafSystems\Wordpress\Plugin\Shield;
7
  use FernleafSystems\Wordpress\Services\Services;
8
+ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
9
 
10
  /**
11
  * Class Controller
12
  * @package FernleafSystems\Wordpress\Plugin\Shield\Controller
13
+ * @property Config\ConfigVO $cfg
14
  * @property bool $is_activating
15
  * @property bool $is_debug
16
  * @property bool $modules_loaded
48
  */
49
  private $sRootFile;
50
 
 
 
 
 
 
51
  /**
52
  * @var string
53
  * @deprecated 10.1
69
  */
70
  protected static $sRequestId;
71
 
 
 
 
 
 
72
  /**
73
  * @var string
74
  */
75
  protected $sAdminNoticeError = '';
76
 
77
  /**
78
+ * @var Shield\Modules\BaseShield\ModCon[]
79
  */
80
  protected $aModules;
81
 
144
  $this->modules = [];
145
 
146
  $this->loadServices();
147
+ $this->loadConfig();
148
+
149
  $this->checkMinimumRequirements();
150
  $this->doRegisterHooks();
151
 
163
 
164
  switch ( $key ) {
165
 
166
+ case 'cfg':
167
+ if ( !$val instanceof Config\ConfigVO ) {
168
+ $val = $this->loadConfig();
169
+ }
170
+ break;
171
+
172
  case 'is_debug':
173
  if ( is_null( $val ) ) {
174
  $val = ( new Shield\Controller\Utilities\DebugMode() )
195
  /**
196
  * @return array
197
  * @throws \Exception
198
+ * @deprecated 10.1.4
199
  */
200
  private function readPluginSpecification() :array {
201
  $spec = [];
221
  $bMeetsRequirements = true;
222
  $aRequirementsMessages = $this->getRequirementsMessages();
223
 
224
+ $php = $this->cfg->requirements[ 'php' ];
225
+ if ( !empty( $php ) ) {
226
+ if ( version_compare( Services::Data()->getPhpVersion(), $php, '<' ) ) {
227
+ $aRequirementsMessages[] = sprintf( 'PHP does not meet minimum version. Your version: %s. Required Version: %s.', PHP_VERSION, $php );
228
  $bMeetsRequirements = false;
229
  }
230
  }
231
 
232
+ $wp = $this->cfg->requirements[ 'wordpress' ];
233
+ if ( !empty( $wp ) ) {
234
  $sWpVersion = Services::WpGeneral()->getVersion( true );
235
+ if ( version_compare( $sWpVersion, $wp, '<' ) ) {
236
+ $aRequirementsMessages[] = sprintf( 'WordPress does not meet minimum version. Your version: %s. Required Version: %s.', $sWpVersion, $wp );
237
  $bMeetsRequirements = false;
238
  }
239
  }
514
  */
515
  public function onWpAdminBarMenu( $oAdminBar ) {
516
  $bShow = apply_filters( $this->prefix( 'show_admin_bar_menu' ),
517
+ $this->isValidAdminArea( true ) && $this->cfg->properties[ 'show_admin_bar_menu' ]
 
518
  );
519
  if ( $bShow ) {
520
  $aMenuItems = apply_filters( $this->prefix( 'admin_bar_menu_items' ), [] );
540
 
541
  public function onWpDashboardSetup() {
542
  $show = apply_filters( $this->prefix( 'show_dashboard_widget' ),
543
+ $this->isValidAdminArea() && $this->cfg->properties[ 'show_dashboard_widget' ]
544
  );
545
  if ( $show ) {
546
  wp_add_dashboard_widget(
612
  * @return bool
613
  */
614
  protected function createPluginMenu() {
615
+ $menu = $this->cfg->menu;
616
 
617
+ if ( apply_filters( $this->prefix( 'filter_hidePluginMenu' ), !$menu[ 'show' ] ) ) {
 
618
  return true;
619
  }
620
 
621
+ if ( $menu[ 'top_level' ] ) {
622
 
623
+ $labels = $this->getLabels();
624
+ $sMenuTitle = empty( $labels[ 'MenuTitle' ] ) ? $menu[ 'title' ] : $labels[ 'MenuTitle' ];
625
  if ( is_null( $sMenuTitle ) ) {
626
  $sMenuTitle = $this->getHumanName();
627
  }
628
 
629
+ $sMenuIcon = $this->getPluginUrl_Image( $menu[ 'icon_image' ] );
630
+ $sIconUrl = empty( $labels[ 'icon_url_16x16' ] ) ? $sMenuIcon : $labels[ 'icon_url_16x16' ];
631
 
632
  $sFullParentMenuId = $this->getPluginPrefix();
633
  add_menu_page(
635
  $sMenuTitle,
636
  $this->getBasePermissions(),
637
  $sFullParentMenuId,
638
+ [ $this, $menu[ 'callback' ] ],
639
  $sIconUrl
640
  );
641
 
642
+ if ( $menu[ 'has_submenu' ] ) {
643
 
644
+ $menuItems = apply_filters( $this->prefix( 'submenu_items' ), [] );
645
+ if ( !empty( $menuItems ) ) {
646
+ foreach ( $menuItems as $sMenuTitle => $aMenu ) {
647
  list( $sMenuItemText, $sMenuItemId, $aMenuCallBack, $bShowItem ) = $aMenu;
648
  add_submenu_page(
649
  $bShowItem ? $sFullParentMenuId : null,
657
  }
658
  }
659
 
660
+ if ( $menu[ 'do_submenu_fix' ] ) {
661
  $this->fixSubmenu();
662
  }
663
  }
688
 
689
  if ( $sPluginFile == $this->getPluginBaseFile() ) {
690
  $sTemplate = '<strong><a href="%s" target="_blank">%s</a></strong>';
691
+ foreach ( $this->cfg->plugin_meta as $aHref ) {
692
  array_push( $aPluginMeta, sprintf( $sTemplate, $aHref[ 'href' ], $aHref[ 'name' ] ) );
693
  }
694
  }
707
  unset( $aActionLinks[ 'edit' ] );
708
  }
709
 
710
+ $links = $this->cfg->action_links[ 'add' ];
711
+ if ( is_array( $links ) ) {
712
 
713
  $bPro = $this->isPremiumActive();
714
  $oDP = Services::Data();
715
  $sLinkTemplate = '<a href="%s" target="%s" title="%s">%s</a>';
716
+ foreach ( $links as $aLink ) {
717
  $aLink = array_merge(
718
  [
719
  'highlight' => false,
755
  }
756
 
757
  public function onWpEnqueueFrontendCss() {
758
+ $includes = $this->cfg->includes[ 'frontend' ];
759
+ if ( isset( $includes[ 'css' ] ) && !empty( $includes[ 'css' ] ) && is_array( $includes[ 'css' ] ) ) {
760
 
761
  $aDeps = [];
762
+ foreach ( $includes[ 'css' ] as $sAsset ) {
763
  $sUrl = $this->getPluginUrl_Css( $sAsset );
764
  if ( !empty( $sUrl ) ) {
765
  $sAsset = $this->prefix( $sAsset );
775
 
776
  $aIncludes = [];
777
  if ( $this->getIsPage_PluginAdmin() ) {
778
+ $includes = $this->cfg->includes[ 'plugin_admin' ];
779
+ if ( !empty( $includes[ 'js' ] ) && is_array( $includes[ 'js' ] ) ) {
780
+ $aIncludes = $includes[ 'js' ];
781
  }
782
  }
783
  elseif ( $this->isValidAdminArea() ) {
784
+ $includes = $this->cfg->includes[ 'admin' ];
785
+ if ( !empty( $includes[ 'js' ] ) && is_array( $includes[ 'js' ] ) ) {
786
+ $aIncludes = $includes[ 'js' ];
787
  }
788
  }
789
 
790
+ $nativeWP = [ 'jquery' ];
 
 
791
 
792
  $aDeps = [];
793
+ foreach ( $aIncludes as $asset ) {
794
 
795
  // Built-in handles
796
+ if ( in_array( $asset, $nativeWP ) ) {
797
+ if ( wp_script_is( $asset, 'registered' ) ) {
798
+ wp_enqueue_script( $asset );
799
+ $aDeps[] = $asset;
800
  }
801
  }
802
  else {
803
+ $sUrl = $this->getPluginUrl_Js( $asset );
804
  if ( !empty( $sUrl ) ) {
805
+ $asset = $this->prefix( $asset );
806
+ wp_register_script( $asset, $sUrl, $aDeps, $this->getVersion() );
807
+ wp_enqueue_script( $asset );
808
+ $aDeps[] = $asset;
809
  }
810
  }
811
  }
815
 
816
  $aIncludes = [];
817
  if ( $this->getIsPage_PluginAdmin() ) {
818
+ $includes = $this->cfg->includes[ 'plugin_admin' ];
819
+ if ( !empty( $includes[ 'css' ] ) && is_array( $includes[ 'css' ] ) ) {
820
+ $aIncludes = $includes[ 'css' ];
821
  }
822
  }
823
  elseif ( $this->isValidAdminArea() ) {
824
+ $includes = $this->cfg->includes[ 'admin' ];
825
+ if ( !empty( $includes[ 'css' ] ) && is_array( $includes[ 'css' ] ) ) {
826
+ $aIncludes = $includes[ 'css' ];
827
  }
828
  }
829
 
830
  $aDeps = [];
831
+ foreach ( $aIncludes as $asset ) {
832
+ $sUrl = $this->getPluginUrl_Css( $asset );
833
  if ( !empty( $sUrl ) ) {
834
+ $asset = $this->prefix( $asset );
835
+ wp_register_style( $asset, $sUrl, $aDeps, $this->getVersion() );
836
+ wp_enqueue_style( $asset );
837
+ $aDeps[] = $asset;
838
  }
839
  }
840
  }
886
  /**
887
  * This will hook into the saving of plugin update information and if there is an update for this plugin, it'll add
888
  * a data stamp to state when the update was first detected.
889
+ * @param \stdClass $data
890
  * @return \stdClass
891
  */
892
+ public function setUpdateFirstDetectedAt( $data ) {
893
 
894
+ if ( !empty( $data ) && !empty( $data->response ) && isset( $data->response[ $this->getPluginBaseFile() ] ) ) {
895
+ // i.e. update available
 
896
 
897
  $new = Services::WpPlugins()->getUpdateNewVersion( $this->getPluginBaseFile() );
898
+ if ( !empty( $new ) && isset( $this->cfg ) ) {
899
+ $updates = $this->cfg->update_first_detected;
900
+ if ( count( $updates ) > 3 ) {
901
+ $updates = [];
902
  }
903
+ if ( !isset( $updates[ $new ] ) ) {
904
+ $updates[ $new ] = Services::Request()->ts();
905
  }
906
+ $this->cfg->update_first_detected = $updates;
907
  }
908
  }
909
 
910
+ return $data;
911
  }
912
 
913
  /**
914
  * This is a filter method designed to say whether WordPress plugin upgrades should be permitted,
915
  * based on the plugin settings.
916
+ * @param bool $isAutoUpdate
917
  * @param string|object $mItem
918
  * @return bool
919
  */
920
+ public function onWpAutoUpdate( $isAutoUpdate, $mItem ) {
921
+ $WP = Services::WpGeneral();
922
  $oWpPlugins = Services::WpPlugins();
923
 
924
+ $sFile = $WP->getFileFromAutomaticUpdateItem( $mItem );
925
 
926
  // The item in question is this plugin...
927
  if ( $sFile === $this->getPluginBaseFile() ) {
928
+ $autoupdateSelf = $this->cfg->properties[ 'autoupdate' ];
929
 
930
+ if ( !$WP->isRunningAutomaticUpdates() && $autoupdateSelf == 'confidence' ) {
931
+ $autoupdateSelf = 'yes'; // so that we appear to be automatically updating
 
 
932
  }
933
 
934
+ $new = $oWpPlugins->getUpdateNewVersion( $sFile );
935
 
936
+ switch ( $autoupdateSelf ) {
937
 
938
  case 'yes' :
939
+ $isAutoUpdate = true;
940
  break;
941
 
942
  case 'block' :
943
+ $isAutoUpdate = false;
944
  break;
945
 
946
  case 'confidence' :
947
+ $isAutoUpdate = false;
948
+ if ( !empty( $new ) ) {
949
+ $firstDetected = $this->cfg->update_first_detected[ $new ] ?? 0;
950
+ $availableFor = Services::Request()->ts() - $firstDetected;
951
+ $isAutoUpdate = $firstDetected > 0
952
+ && $availableFor > DAY_IN_SECONDS*$this->cfg->properties[ 'autoupdate_days' ];
953
  }
954
  break;
955
 
958
  break;
959
  }
960
  }
961
+ return $isAutoUpdate;
962
  }
963
 
964
  /**
984
 
985
  public function getLabels() :array {
986
 
987
+ $labels = array_map(
988
+ 'stripslashes',
989
+ apply_filters( $this->prefix( 'plugin_labels' ), $this->cfg->labels )
990
+ );
991
 
992
  $oDP = Services::Data();
993
  foreach ( [ '16x16', '32x32', '128x128' ] as $dimension ) {
1027
  /**
1028
  * Added to a WordPress filter ('all_plugins') which will remove this particular plugin from the
1029
  * list of all plugins based on the "plugin file" name.
1030
+ * @param array $plugins
1031
  * @return array
1032
  */
1033
+ public function filter_hidePluginFromTableList( $plugins ) {
1034
+ if ( apply_filters( $this->prefix( 'hide_plugin' ), false ) ) {
1035
+ unset( $plugins[ $this->getPluginBaseFile() ] );
 
 
 
 
 
 
 
1036
  }
1037
+ return $plugins;
1038
  }
1039
 
1040
  /**
1042
  * from the WordPress Admin UI.
1043
  * In order to ensure that WordPress still checks for plugin updates it will not remove this plugin from
1044
  * the list of plugins if DOING_CRON is set to true.
1045
+ * @param \stdClass $plugins
1046
  * @return \stdClass
 
1047
  */
1048
+ public function filter_hidePluginUpdatesFromUI( $plugins ) {
1049
+ if ( !Services::WpGeneral()->isCron() && apply_filters( $this->prefix( 'hide_plugin_updates' ), false ) ) {
1050
+ unset( $plugins->response[ $this->getPluginBaseFile() ] );
 
1051
  }
1052
+ return $plugins;
 
 
 
 
 
 
1053
  }
1054
 
1055
  /**
1056
+ * @param string $suffix
1057
+ * @param string $glue
1058
  * @return string
1059
  */
1060
+ public function prefix( $suffix = '', $glue = '-' ) {
1061
+ $sPrefix = $this->getPluginPrefix( $glue );
1062
 
1063
+ if ( $suffix == $sPrefix || strpos( $suffix, $sPrefix.$glue ) === 0 ) { //it already has the full prefix
1064
+ return $suffix;
1065
  }
1066
 
1067
+ return sprintf( '%s%s%s', $sPrefix, empty( $suffix ) ? '' : $glue, empty( $suffix ) ? '' : $suffix );
1068
  }
1069
 
1070
  public function prefixOption( string $suffix = '' ) :string {
1071
  return $this->prefix( $suffix, '_' );
1072
  }
1073
 
1074
+ /**
1075
+ * @return Config\ConfigVO
1076
+ * @throws \Exception
1077
+ */
1078
+ private function loadConfig() :Config\ConfigVO {
1079
+ $this->cfg = ( new Config\Ops\LoadConfig( $this->getPathPluginSpec(), $this->getConfigStoreKey() ) )
1080
+ ->setCon( $this )
1081
+ ->run();
1082
+ $this->rebuild_options = $this->cfg->rebuilt;
1083
+ return $this->cfg;
1084
+ }
1085
+
1086
  /**
1087
  * @return array
1088
+ * @deprecated 10.2
1089
  */
1090
  public function getPluginSpec() {
1091
+ if ( isset( $this->cfg ) ) {
1092
+ return $this->cfg->getRawDataAsArray();
1093
+ }
1094
  return $this->getPluginControllerOptions()->plugin_spec;
1095
  }
1096
 
1097
+ /**
1098
+ * @param string $key
1099
+ * @return array
1100
+ * @deprecated 10.1.4
1101
+ */
1102
  protected function getPluginSpec_ActionLinks( string $key ) :array {
1103
  $aData = $this->getPluginSpec()[ 'action_links' ];
1104
  return $aData[ $key ] ?? [];
1107
  /**
1108
  * @param string $key
1109
  * @return mixed|null
1110
+ * @deprecated 10.1.4
1111
  */
1112
  protected function getPluginSpec_Include( string $key ) {
1113
  $aData = $this->getPluginSpec()[ 'includes' ];
1117
  /**
1118
  * @param string $key
1119
  * @return array|string
1120
+ * @deprecated 10.1.4
1121
  */
1122
  protected function getPluginSpec_Labels( string $key = '' ) {
1123
  $oSpec = $this->getPluginSpec();
1133
  /**
1134
  * @param string $key
1135
  * @return mixed|null
1136
+ * @deprecated 10.1.4
1137
  */
1138
  protected function getPluginSpec_Menu( string $key ) {
1139
  $aData = $this->getPluginSpec()[ 'menu' ];
1145
  * @return string|null
1146
  */
1147
  public function getPluginSpec_Path( string $key ) {
1148
+ if ( isset( $this->cfg ) ) {
1149
+ return $this->cfg->paths[ $key ];
1150
+ }
1151
  $aData = $this->getPluginSpec()[ 'paths' ];
1152
  return $aData[ $key ] ?? null;
1153
  }
1156
  * @param string $key
1157
  * @return mixed|null
1158
  */
1159
+ protected function getCfgProperty( string $key ) {
1160
+ return $this->cfg->properties[ $key ] ?? null;
1161
+ }
1162
+
1163
+ /**
1164
+ * @param string $key
1165
+ * @return mixed|null
1166
+ * @deprecated 10.1.4 - getCfgProperty()
1167
+ */
1168
  protected function getPluginSpec_Property( string $key ) {
1169
+ if ( isset( $this->cfg ) ) {
1170
+ return $this->cfg->properties[ $key ];
1171
+ }
1172
  $data = $this->getPluginSpec()[ 'properties' ];
1173
  return $data[ $key ] ?? null;
1174
  }
1175
 
1176
  /**
1177
  * @return array
1178
+ * @deprecated 10.1.4
1179
  */
1180
  protected function getPluginSpec_PluginMeta() {
1181
  $aSpec = $this->getPluginSpec();
1185
  /**
1186
  * @param string $key
1187
  * @return mixed|null
1188
+ * @deprecated 10.1.4
1189
  */
1190
  protected function getPluginSpec_Requirement( string $key ) {
1191
  $aData = $this->getPluginSpec()[ 'requirements' ];
1193
  }
1194
 
1195
  public function getBasePermissions() :string {
1196
+ if ( isset( $this->cfg ) ) {
1197
+ return $this->cfg->properties[ 'base_permissions' ];
1198
+ }
1199
  return $this->getPluginSpec_Property( 'base_permissions' );
1200
  }
1201
 
1234
  * current_user_can() never gets caught up in an infinite loop of permissions checking
1235
  */
1236
  public function getMeetsBasePermissions() :bool {
1237
+ if ( did_action( 'init' ) && !isset( $this->user_can_base_permissions ) ) {
1238
  $this->user_can_base_permissions = current_user_can( $this->getBasePermissions() );
 
1239
  }
1240
  return (bool)$this->user_can_base_permissions;
1241
  }
1275
  return Services::WpGeneral()->getCurrentWpAdminPage() === $this->getPluginPrefix();
1276
  }
1277
 
1278
+ /**
1279
+ * @return bool
1280
+ * @deprecated 10.1.4
1281
+ */
1282
  public function getIsRebuildOptionsFromFile() :bool {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1283
  return $this->rebuild_options;
1284
  }
1285
 
1458
  return $this->getPluginSpec_Property( 'version' );
1459
  }
1460
 
1461
+ /**
1462
+ * @return string
1463
+ * @deprecated 10.1.4
1464
+ */
1465
  public function getPreviousVersion() :string {
1466
  $opts = $this->getPluginControllerOptions();
1467
  if ( empty( $opts->previous_version ) ) {
1484
  * @return \stdClass
1485
  */
1486
  public function getPluginControllerOptions() {
 
 
 
 
 
 
 
 
 
 
 
1487
  return self::$oControllerOptions;
1488
  }
1489
 
1521
  protected function saveCurrentPluginControllerOptions() {
1522
  $WP = Services::WpGeneral();
1523
  add_filter( $this->prefix( 'bypass_is_plugin_admin' ), '__return_true' );
1524
+
1525
  if ( $this->plugin_deleting ) {
1526
+ Transient::Delete( $this->getConfigStoreKey() );
1527
+ }
1528
+ elseif ( isset( $this->cfg ) ) {
1529
+ Config\Ops\Save::ToWp( $this->cfg, $this->getConfigStoreKey() );
1530
  }
1531
  else {
1532
+ /* @deprecated 10.1.4 */
1533
  $WP->updateOption(
1534
  $this->getPluginControllerOptionsKey(),
1535
  $this->getPluginControllerOptions()
1548
  return $this;
1549
  }
1550
 
1551
+ private function getConfigStoreKey() :string {
1552
+ return 'aptoweb_controller_'.substr( md5( get_class() ), 0, 6 );
1553
+ }
1554
+
1555
  /**
1556
  * @return string
1557
+ * @deprecated 10.1.4
1558
  */
1559
  private function getPluginControllerOptionsKey() {
1560
  return strtolower( get_class() );
1954
  private function buildPrivacyPolicyContent() {
1955
  try {
1956
  if ( $this->getModule_SecAdmin()->isWlEnabled() ) {
1957
+ $name = $this->getHumanName();
1958
+ $href = $this->getLabels()[ 'PluginURI' ];
1959
  }
1960
  else {
1961
+ $name = $this->cfg->menu[ 'title' ];
1962
+ $href = $this->cfg->meta[ 'privacy_policy_href' ];
1963
  }
1964
 
1965
  /** @var Shield\Modules\AuditTrail\Options $oOpts */
1966
+ $oOpts = $this->getModule_AuditTrail()->getOptions();
1967
+
1968
+ $content = $this->getRenderer()
1969
+ ->setTemplate( 'snippets/privacy_policy' )
1970
+ ->setTemplateEngineTwig()
1971
+ ->setRenderVars(
1972
+ [
1973
+ 'name' => $name,
1974
+ 'href' => $href,
1975
+ 'audit_trail_days' => $oOpts->getAutoCleanDays()
1976
+ ]
1977
+ )
1978
+ ->render();
1979
+ }
1980
+ catch ( \Exception $e ) {
1981
+ $content = '';
1982
+ }
1983
+ return empty( $content ) ? '' : wp_kses_post( wpautop( $content, false ) );
 
1984
  }
1985
 
1986
  private function runTests() {
src/lib/src/Controller/Utilities/Upgrade.php CHANGED
@@ -12,7 +12,7 @@ class Upgrade {
12
  protected function run() {
13
  $con = $this->getCon();
14
 
15
- if ( $con->getPreviousVersion() !== $con->getVersion() ) {
16
  foreach ( $con->modules as $mod ) {
17
  $H = $mod->getUpgradeHandler();
18
  if ( $H instanceof Shield\Modules\Base\Upgrade ) {
@@ -21,6 +21,6 @@ class Upgrade {
21
  }
22
  }
23
 
24
- $con->getPluginControllerOptions()->previous_version = $con->getVersion();
25
  }
26
  }
12
  protected function run() {
13
  $con = $this->getCon();
14
 
15
+ if ( $con->cfg->previous_version !== $con->getVersion() ) {
16
  foreach ( $con->modules as $mod ) {
17
  $H = $mod->getUpgradeHandler();
18
  if ( $H instanceof Shield\Modules\Base\Upgrade ) {
21
  }
22
  }
23
 
24
+ $con->cfg->previous_version = $con->getVersion();
25
  }
26
  }
src/lib/src/Modules/AuditTrail/Auditors/Users.php CHANGED
@@ -11,6 +11,8 @@ class Users extends Base {
11
 
12
  public function run() {
13
  $this->setupLoginCaptureHooks();
 
 
14
  add_action( 'user_register', [ $this, 'auditNewUserRegistered' ] );
15
  add_action( 'delete_user', [ $this, 'auditDeleteUser' ], 30, 2 );
16
  }
@@ -21,7 +23,7 @@ class Users extends Base {
21
 
22
  public function auditUserLoginSuccess( \WP_User $user ) {
23
  $this->getCon()->fireEvent(
24
- 'user_login',
25
  [
26
  'audit' => [
27
  'user' => $user->user_login,
11
 
12
  public function run() {
13
  $this->setupLoginCaptureHooks();
14
+ $this->setToCaptureApplicationLogin( true );
15
+
16
  add_action( 'user_register', [ $this, 'auditNewUserRegistered' ] );
17
  add_action( 'delete_user', [ $this, 'auditDeleteUser' ], 30, 2 );
18
  }
23
 
24
  public function auditUserLoginSuccess( \WP_User $user ) {
25
  $this->getCon()->fireEvent(
26
+ Services::WpUsers()->isAppPasswordAuth() ? 'user_login_app' : 'user_login',
27
  [
28
  'audit' => [
29
  'user' => $user->user_login,
src/lib/src/Modules/AuditTrail/Strings.php CHANGED
@@ -29,7 +29,7 @@ class Strings extends Base\Strings {
29
  'theme_file_edited' => [
30
  __( 'An attempt was made to edit the theme file "%s" directly through the WordPress editor.', 'wp-simple-firewall' )
31
  ],
32
- 'theme_upgraded' => [
33
  __( 'Theme "%s" was upgraded from version %s to version %s.', 'wp-simple-firewall' )
34
  ],
35
  'core_updated' => [
@@ -64,6 +64,9 @@ class Strings extends Base\Strings {
64
  'user_login' => [
65
  __( 'Attempted user login by "%s" was successful.', 'wp-simple-firewall' ),
66
  ],
 
 
 
67
  'user_registered' => [
68
  __( 'New WordPress user registered.', 'wp-simple-firewall' )
69
  .' '.__( 'New username is "%s" with email address "%s".', 'wp-simple-firewall' )
29
  'theme_file_edited' => [
30
  __( 'An attempt was made to edit the theme file "%s" directly through the WordPress editor.', 'wp-simple-firewall' )
31
  ],
32
+ 'theme_upgraded' => [
33
  __( 'Theme "%s" was upgraded from version %s to version %s.', 'wp-simple-firewall' )
34
  ],
35
  'core_updated' => [
64
  'user_login' => [
65
  __( 'Attempted user login by "%s" was successful.', 'wp-simple-firewall' ),
66
  ],
67
+ 'user_login_app' => [
68
+ __( 'Attempted login by "%s" using application password was successful.', 'wp-simple-firewall' ),
69
+ ],
70
  'user_registered' => [
71
  __( 'New WordPress user registered.', 'wp-simple-firewall' )
72
  .' '.__( 'New username is "%s" with email address "%s".', 'wp-simple-firewall' )
src/lib/src/Modules/Autoupdates/Insights/OverviewCards.php CHANGED
@@ -135,7 +135,7 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
135
  'summary' => $nCount > 0 ?
136
  sprintf( __( 'There are %s inactive and unused themes', 'wp-simple-firewall' ), $nCount )
137
  : __( "There appears to be no unused themes", 'wp-simple-firewall' ),
138
- 'href' => Services::WpGeneral()->getAdminUrl_Plugins( true ),
139
  'help' => __( 'Unused themes should be removed.', 'wp-simple-firewall' )
140
  ];
141
 
135
  'summary' => $nCount > 0 ?
136
  sprintf( __( 'There are %s inactive and unused themes', 'wp-simple-firewall' ), $nCount )
137
  : __( "There appears to be no unused themes", 'wp-simple-firewall' ),
138
+ 'href' => Services::WpGeneral()->getAdminUrl_Themes( true ),
139
  'help' => __( 'Unused themes should be removed.', 'wp-simple-firewall' )
140
  ];
141
 
src/lib/src/Modules/Base/Upgrade.php CHANGED
@@ -28,8 +28,8 @@ class Upgrade {
28
  */
29
  protected function upgradeModule() {
30
  $con = $this->getCon();
31
- $previous = $con->getPreviousVersion();
32
- foreach ( $con->getPluginSpec()[ 'version_upgrades' ] as $version ) {
33
  $upgradeMethod = 'upgrade_'.str_replace( '.', '', $version );
34
  if ( version_compare( $previous, $version, '<' ) && method_exists( $this, $upgradeMethod ) ) {
35
  $this->{$upgradeMethod}();
28
  */
29
  protected function upgradeModule() {
30
  $con = $this->getCon();
31
+ $previous = $con->cfg->previous_version;
32
+ foreach ( $con->cfg->version_upgrades as $version ) {
33
  $upgradeMethod = 'upgrade_'.str_replace( '.', '', $version );
34
  if ( version_compare( $previous, $version, '<' ) && method_exists( $this, $upgradeMethod ) ) {
35
  $this->{$upgradeMethod}();
src/lib/src/Modules/BaseShield/ModCon.php CHANGED
@@ -196,7 +196,10 @@ class ModCon extends Base\ModCon {
196
  public function isVisitorWhitelisted() :bool {
197
  if ( !isset( self::$bVisitorIsWhitelisted ) ) {
198
  try {
199
- $ipID = ( new IpIdentify( (string)Services::IP()->getRequestIp() ) )->run();
 
 
 
200
  $ipID = key( $ipID );
201
  }
202
  catch ( \Exception $e ) {
@@ -204,7 +207,7 @@ class ModCon extends Base\ModCon {
204
  }
205
 
206
  self::$bVisitorIsWhitelisted =
207
- in_array( $ipID, [ IpIdentify::ICONTROLWP ] )
208
  || ( new Shield\Modules\IPs\Lib\Ops\LookupIpOnList() )
209
  ->setDbHandler( $this->getCon()->getModule_IPs()->getDbHandler_IPs() )
210
  ->setIP( Services::IP()->getRequestIp() )
196
  public function isVisitorWhitelisted() :bool {
197
  if ( !isset( self::$bVisitorIsWhitelisted ) ) {
198
  try {
199
+ $ipID = ( new IpIdentify(
200
+ (string)Services::IP()->getRequestIp(),
201
+ (string)Services::Request()->getUserAgent()
202
+ ) )->run();
203
  $ipID = key( $ipID );
204
  }
205
  catch ( \Exception $e ) {
207
  }
208
 
209
  self::$bVisitorIsWhitelisted =
210
+ in_array( $ipID, [ IpIdentify::ICONTROLWP, IpIdentify::MANAGEWP ] )
211
  || ( new Shield\Modules\IPs\Lib\Ops\LookupIpOnList() )
212
  ->setDbHandler( $this->getCon()->getModule_IPs()->getDbHandler_IPs() )
213
  ->setIP( Services::IP()->getRequestIp() )
src/lib/src/Modules/CommentsFilter/ModCon.php CHANGED
@@ -78,7 +78,7 @@ class ModCon extends BaseShield\ModCon {
78
  public function isEnabledCaptcha() :bool {
79
  /** @var Options $opts */
80
  $opts = $this->getOptions();
81
- return $this->isModOptEnabled() && !$opts->isEnabledCaptcha()
82
  && $this->getCaptchaCfg()->ready;
83
  }
84
 
78
  public function isEnabledCaptcha() :bool {
79
  /** @var Options $opts */
80
  $opts = $this->getOptions();
81
+ return $this->isModOptEnabled() && $opts->isEnabledCaptcha()
82
  && $this->getCaptchaCfg()->ready;
83
  }
84
 
src/lib/src/Modules/Email/Processor.php CHANGED
@@ -179,6 +179,9 @@ class Processor extends BaseShield\Processor {
179
  if ( !empty( $proposed ) ) {
180
  $name = $proposed;
181
  }
 
 
 
182
  else {
183
  $name = sprintf( '%s - %s', $name, $this->getCon()->getHumanName() );
184
  }
179
  if ( !empty( $proposed ) ) {
180
  $name = $proposed;
181
  }
182
+ elseif ( empty( $name ) ) {
183
+ $name = $this->getCon()->getHumanName();
184
+ }
185
  else {
186
  $name = sprintf( '%s - %s', $name, $this->getCon()->getHumanName() );
187
  }
src/lib/src/Modules/Events/Strings.php CHANGED
@@ -251,6 +251,7 @@ class Strings extends Base\Strings {
251
  'post_published' => __( 'Post Published', 'wp-simple-firewall' ),
252
  'post_unpublished' => __( 'Post Unpublished', 'wp-simple-firewall' ),
253
  'user_login' => __( 'User Login', 'wp-simple-firewall' ),
 
254
  'user_registered' => __( 'User Registered', 'wp-simple-firewall' ),
255
  'user_deleted' => __( 'User Deleted', 'wp-simple-firewall' ),
256
  'user_deleted_reassigned' => __( 'User Deleted And Reassigned', 'wp-simple-firewall' ),
251
  'post_published' => __( 'Post Published', 'wp-simple-firewall' ),
252
  'post_unpublished' => __( 'Post Unpublished', 'wp-simple-firewall' ),
253
  'user_login' => __( 'User Login', 'wp-simple-firewall' ),
254
+ 'user_login_app' => __( 'User Login By App Password', 'wp-simple-firewall' ),
255
  'user_registered' => __( 'User Registered', 'wp-simple-firewall' ),
256
  'user_deleted' => __( 'User Deleted', 'wp-simple-firewall' ),
257
  'user_deleted_reassigned' => __( 'User Deleted And Reassigned', 'wp-simple-firewall' ),
src/lib/src/Modules/Firewall/Processor.php CHANGED
@@ -40,7 +40,7 @@ class Processor extends BaseShield\Processor {
40
  }
41
 
42
  private function getIfDoFirewallBlock() :bool {
43
- return !$this->isVisitorRequestPermitted();
44
  }
45
 
46
  private function getIfPerformFirewallScan() :bool {
40
  }
41
 
42
  private function getIfDoFirewallBlock() :bool {
43
+ return apply_filters( 'icwp_shield_do_firewall_block', !$this->isVisitorRequestPermitted() );
44
  }
45
 
46
  private function getIfPerformFirewallScan() :bool {
src/lib/src/Modules/IPs/Lib/BlockRequest.php CHANGED
@@ -69,7 +69,7 @@ class BlockRequest {
69
  $homeURL = $con->getLabels()[ 'PluginURI' ];
70
  }
71
  else {
72
- $homeURL = $con->getPluginSpec()[ 'meta' ][ 'url_repo_home' ];
73
  }
74
 
75
  $data = [
69
  $homeURL = $con->getLabels()[ 'PluginURI' ];
70
  }
71
  else {
72
+ $homeURL = $con->cfg->meta[ 'url_repo_home' ];
73
  }
74
 
75
  $data = [
src/lib/src/Modules/Insights/UI.php CHANGED
@@ -248,7 +248,7 @@ class UI extends BaseShield\UI {
248
  'page_title' => $pageTitle
249
  ],
250
  'vars' => [
251
- 'changelog_id' => $con->getPluginSpec()[ 'meta' ][ 'announcekit_changelog_id' ],
252
  'mods' => $this->buildSelectData_ModuleSettings(),
253
  'search_select' => $this->buildSelectData_OptionsSearch(),
254
  'active_module_settings' => $subNavSection
248
  'page_title' => $pageTitle
249
  ],
250
  'vars' => [
251
+ 'changelog_id' => $con->cfg->meta[ 'announcekit_changelog_id' ],
252
  'mods' => $this->buildSelectData_ModuleSettings(),
253
  'search_select' => $this->buildSelectData_OptionsSearch(),
254
  'active_module_settings' => $subNavSection
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php CHANGED
@@ -53,7 +53,8 @@ class MfaController {
53
  private function captureLoginIntent( \WP_User $user ) {
54
  /** @var LoginGuard\Options $opts */
55
  $opts = $this->getOptions();
56
- if ( $this->isSubjectToLoginIntent( $user ) && !$this->canUserMfaSkip( $user ) ) {
 
57
 
58
  $providers = $this->getProvidersForUser( $user );
59
  if ( !empty( $providers ) ) {
53
  private function captureLoginIntent( \WP_User $user ) {
54
  /** @var LoginGuard\Options $opts */
55
  $opts = $this->getOptions();
56
+ if ( $this->isSubjectToLoginIntent( $user )
57
+ && !Services::WpUsers()->isAppPasswordAuth() && !$this->canUserMfaSkip( $user ) ) {
58
 
59
  $providers = $this->getProvidersForUser( $user );
60
  if ( !empty( $providers ) ) {
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaSkip.php CHANGED
@@ -38,18 +38,18 @@ class MfaSkip {
38
  * @return bool
39
  */
40
  public function canMfaSkip( \WP_User $oUser ) {
41
- /** @var LoginGuard\Options $oOpts */
42
- $oOpts = $this->getOptions();
43
- $oReq = Services::Request();
44
 
45
  $bCanSkip = false;
46
 
47
- if ( $oOpts->isMfaSkip() ) {
48
  $sAgentHash = $this->getAgentHash();
49
  $oMeta = $this->getCon()->getUserMeta( $oUser );
50
  $aHashes = is_array( $oMeta->hash_loginmfa ) ? $oMeta->hash_loginmfa : [];
51
  $bCanSkip = isset( $aHashes[ $sAgentHash ] )
52
- && ( (int)$aHashes[ $sAgentHash ] + $oOpts->getMfaSkip() ) > $oReq->ts();
53
  }
54
 
55
  return $bCanSkip;
38
  * @return bool
39
  */
40
  public function canMfaSkip( \WP_User $oUser ) {
41
+ /** @var LoginGuard\Options $opts */
42
+ $opts = $this->getOptions();
43
+ $req = Services::Request();
44
 
45
  $bCanSkip = false;
46
 
47
+ if ( $opts->isMfaSkip() ) {
48
  $sAgentHash = $this->getAgentHash();
49
  $oMeta = $this->getCon()->getUserMeta( $oUser );
50
  $aHashes = is_array( $oMeta->hash_loginmfa ) ? $oMeta->hash_loginmfa : [];
51
  $bCanSkip = isset( $aHashes[ $sAgentHash ] )
52
+ && ( (int)$aHashes[ $sAgentHash ] + $opts->getMfaSkip() ) > $req->ts();
53
  }
54
 
55
  return $bCanSkip;
src/lib/src/Modules/Plugin/AdminNotices.php CHANGED
@@ -6,6 +6,7 @@ use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\AdminNotices\NoticeVO;
8
  use FernleafSystems\Wordpress\Services\Services;
 
9
 
10
  class AdminNotices extends Shield\Modules\Base\AdminNotices {
11
 
@@ -16,6 +17,10 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
16
 
17
  switch ( $notice->id ) {
18
 
 
 
 
 
19
  case 'php7':
20
  $this->buildNotice_Php7( $notice );
21
  break;
@@ -82,18 +87,42 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
82
  return $this->ajaxExec_DismissAdminNotice();
83
  }
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  private function buildNotice_Php7( NoticeVO $notice ) {
86
- $sName = $this->getCon()->getHumanName();
87
 
88
  $notice->render_data = [
89
  'notice_attributes' => [],
90
  'strings' => [
91
  'title' => sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ),
92
- sprintf( __( "%s 10+ Wont Be Available For Your Site", 'wp-simple-firewall' ), $sName ) ),
93
  'lines' => [
94
  sprintf(
95
  __( '%s 10 wont support old versions of PHP, including yours (PHP: %s).', 'wp-simple-firewall' ),
96
- $sName, Services::Data()->getPhpVersionCleaned( true ), '10'
97
  ),
98
  __( "We recommended updating your server's PHP version ASAP.", 'wp-simple-firewall' )
99
  .' '.__( "Your webhost will be able to help guide you in this.", 'wp-simple-firewall' ),
@@ -107,16 +136,16 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
107
  }
108
 
109
  private function buildNotice_OverrideForceoff( NoticeVO $notice ) {
110
- $sName = $this->getCon()->getHumanName();
111
 
112
  $notice->render_data = [
113
  'notice_attributes' => [],
114
  'strings' => [
115
- 'title' => sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ), sprintf( __( '%s is not protecting your site', 'wp-simple-firewall' ), $sName ) ),
116
  'message' => sprintf(
117
  __( 'Please delete the "%s" file to reactivate %s protection', 'wp-simple-firewall' ),
118
  'forceOff',
119
- $sName
120
  ),
121
  'delete' => __( 'Click here to automatically delete the file', 'wp-simple-firewall' )
122
  ],
@@ -146,16 +175,16 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
146
  }
147
 
148
  private function buildNotice_CompatSgOptimize( NoticeVO $notice ) {
149
- $sName = $this->getCon()->getHumanName();
150
 
151
  $notice->render_data = [
152
  'notice_attributes' => [],
153
  'strings' => [
154
  'title' => sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ),
155
- sprintf( __( 'Site Ground Optimizer plugin has a conflict', 'wp-simple-firewall' ), $sName ) ),
156
  'message' => sprintf(
157
  __( 'The SG Optimizer plugin has 2 settings which are breaking your site and certain %s features.', 'wp-simple-firewall' ),
158
- $sName
159
  )
160
  .' '.sprintf( 'The problematic options are: "Defer Render-blocking JS" and "Remove Query Strings From Static Resources".' ),
161
  'learn_more' => sprintf( 'Click here to learn more' ),
@@ -171,8 +200,8 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
171
  /** @var Options $oOpts */
172
  $oOpts = $this->getOptions();
173
 
174
- $sName = $this->getCon()->getHumanName();
175
- $oUser = Services::WpUsers()->getCurrentWpUser();
176
 
177
  $notice->render_data = [
178
  'notice_attributes' => [],
@@ -184,7 +213,7 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
184
  'signup' => __( 'Sign-Up', 'wp-simple-firewall' ),
185
  'dismiss' => "No thanks, I'm not interested in such informative groups",
186
  'summary' => sprintf( 'The %s team is helping raise awareness of WP Security issues
187
- and to provide guidance with the %s plugin.', $sName, $sName ),
188
  'privacy_policy' => sprintf(
189
  'I certify that I have read and agree to the <a href="%s" target="_blank">Privacy Policy</a>',
190
  $oOpts->getDef( 'href_privacy_policy' )
@@ -196,19 +225,19 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
196
  ],
197
  'install_days' => $oOpts->getInstallationDays(),
198
  'vars' => [
199
- 'name' => $oUser->first_name,
200
- 'user_email' => $oUser->user_email,
201
  'drip_form_id' => $notice->drip_form_id
202
  ]
203
  ];
204
  }
205
 
206
  private function buildNotice_UpdateAvailable( NoticeVO $notice ) {
207
- $sName = $this->getCon()->getHumanName();
208
  $notice->render_data = [
209
  'notice_attributes' => [],
210
  'strings' => [
211
- 'title' => sprintf( __( 'Update available for the %s plugin', 'wp-simple-firewall' ), $sName ),
212
  'click_update' => __( 'Please click to update immediately', 'wp-simple-firewall' ),
213
  'dismiss' => __( 'Dismiss this notice', 'wp-simple-firewall' )
214
  ],
@@ -219,14 +248,14 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
219
  }
220
 
221
  private function buildNotice_WelcomeWizard( NoticeVO $notice ) {
222
- $sName = $this->getCon()->getHumanName();
223
  $notice->render_data = [
224
  'notice_attributes' => [],
225
  'strings' => [
226
  'dismiss' => __( "I don't need the setup wizard just now", 'wp-simple-firewall' ),
227
- 'title' => sprintf( __( 'Get started quickly with the %s Setup Wizard', 'wp-simple-firewall' ), $sName ),
228
- 'setup' => sprintf( __( 'The welcome wizard will help you get setup quickly and become familiar with some of the core %s features', 'wp-simple-firewall' ), $sName ),
229
- 'launch' => sprintf( __( "Launch the welcome wizard", 'wp-simple-firewall' ), $sName ),
230
  ],
231
  'hrefs' => [
232
  'wizard' => $this->getMod()->getUrl_Wizard( 'welcome' ),
@@ -287,6 +316,10 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
287
 
288
  switch ( $notice->id ) {
289
 
 
 
 
 
290
  case 'override-forceoff':
291
  $needed = $oCon->getIfForceOffActive();
292
  break;
@@ -317,4 +350,21 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
317
  }
318
  return $needed;
319
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  }
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\AdminNotices\NoticeVO;
8
  use FernleafSystems\Wordpress\Services\Services;
9
+ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
10
 
11
  class AdminNotices extends Shield\Modules\Base\AdminNotices {
12
 
17
 
18
  switch ( $notice->id ) {
19
 
20
+ case 'plugin-too-old':
21
+ $this->buildNotice_PluginTooOld( $notice );
22
+ break;
23
+
24
  case 'php7':
25
  $this->buildNotice_Php7( $notice );
26
  break;
87
  return $this->ajaxExec_DismissAdminNotice();
88
  }
89
 
90
+ private function buildNotice_PluginTooOld( NoticeVO $notice ) {
91
+ $name = $this->getCon()->getHumanName();
92
+
93
+ $notice->render_data = [
94
+ 'notice_attributes' => [],
95
+ 'strings' => [
96
+ 'title' => sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ),
97
+ sprintf( __( "%s Plugin Is Too Old", 'wp-simple-firewall' ), $name ) ),
98
+ 'lines' => [
99
+ sprintf(
100
+ __( 'There are at least 2 major upgrades to the %s plugin since your version.', 'wp-simple-firewall' ),
101
+ $name
102
+ ),
103
+ __( "We recommended keeping your Shield plugin up-to-date with the latest features.", 'wp-simple-firewall' )
104
+ .' '.__( "We can't support old versions of Shield and certain features may not be working properly as our API develops.", 'wp-simple-firewall' ),
105
+ ],
106
+ 'click_update' => __( 'Click here to go to the WordPress updates page', 'wp-simple-firewall' )
107
+ ],
108
+ 'hrefs' => [
109
+ 'click_update' => Services::WpGeneral()->getAdminUrl_Updates()
110
+ ]
111
+ ];
112
+ }
113
+
114
  private function buildNotice_Php7( NoticeVO $notice ) {
115
+ $name = $this->getCon()->getHumanName();
116
 
117
  $notice->render_data = [
118
  'notice_attributes' => [],
119
  'strings' => [
120
  'title' => sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ),
121
+ sprintf( __( "%s 10+ Wont Be Available For Your Site", 'wp-simple-firewall' ), $name ) ),
122
  'lines' => [
123
  sprintf(
124
  __( '%s 10 wont support old versions of PHP, including yours (PHP: %s).', 'wp-simple-firewall' ),
125
+ $name, Services::Data()->getPhpVersionCleaned( true )
126
  ),
127
  __( "We recommended updating your server's PHP version ASAP.", 'wp-simple-firewall' )
128
  .' '.__( "Your webhost will be able to help guide you in this.", 'wp-simple-firewall' ),
136
  }
137
 
138
  private function buildNotice_OverrideForceoff( NoticeVO $notice ) {
139
+ $name = $this->getCon()->getHumanName();
140
 
141
  $notice->render_data = [
142
  'notice_attributes' => [],
143
  'strings' => [
144
+ 'title' => sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ), sprintf( __( '%s is not protecting your site', 'wp-simple-firewall' ), $name ) ),
145
  'message' => sprintf(
146
  __( 'Please delete the "%s" file to reactivate %s protection', 'wp-simple-firewall' ),
147
  'forceOff',
148
+ $name
149
  ),
150
  'delete' => __( 'Click here to automatically delete the file', 'wp-simple-firewall' )
151
  ],
175
  }
176
 
177
  private function buildNotice_CompatSgOptimize( NoticeVO $notice ) {
178
+ $name = $this->getCon()->getHumanName();
179
 
180
  $notice->render_data = [
181
  'notice_attributes' => [],
182
  'strings' => [
183
  'title' => sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ),
184
+ sprintf( __( 'Site Ground Optimizer plugin has a conflict', 'wp-simple-firewall' ), $name ) ),
185
  'message' => sprintf(
186
  __( 'The SG Optimizer plugin has 2 settings which are breaking your site and certain %s features.', 'wp-simple-firewall' ),
187
+ $name
188
  )
189
  .' '.sprintf( 'The problematic options are: "Defer Render-blocking JS" and "Remove Query Strings From Static Resources".' ),
190
  'learn_more' => sprintf( 'Click here to learn more' ),
200
  /** @var Options $oOpts */
201
  $oOpts = $this->getOptions();
202
 
203
+ $name = $this->getCon()->getHumanName();
204
+ $user = Services::WpUsers()->getCurrentWpUser();
205
 
206
  $notice->render_data = [
207
  'notice_attributes' => [],
213
  'signup' => __( 'Sign-Up', 'wp-simple-firewall' ),
214
  'dismiss' => "No thanks, I'm not interested in such informative groups",
215
  'summary' => sprintf( 'The %s team is helping raise awareness of WP Security issues
216
+ and to provide guidance with the %s plugin.', $name, $name ),
217
  'privacy_policy' => sprintf(
218
  'I certify that I have read and agree to the <a href="%s" target="_blank">Privacy Policy</a>',
219
  $oOpts->getDef( 'href_privacy_policy' )
225
  ],
226
  'install_days' => $oOpts->getInstallationDays(),
227
  'vars' => [
228
+ 'name' => $user->first_name,
229
+ 'user_email' => $user->user_email,
230
  'drip_form_id' => $notice->drip_form_id
231
  ]
232
  ];
233
  }
234
 
235
  private function buildNotice_UpdateAvailable( NoticeVO $notice ) {
236
+ $name = $this->getCon()->getHumanName();
237
  $notice->render_data = [
238
  'notice_attributes' => [],
239
  'strings' => [
240
+ 'title' => sprintf( __( 'Update available for the %s plugin', 'wp-simple-firewall' ), $name ),
241
  'click_update' => __( 'Please click to update immediately', 'wp-simple-firewall' ),
242
  'dismiss' => __( 'Dismiss this notice', 'wp-simple-firewall' )
243
  ],
248
  }
249
 
250
  private function buildNotice_WelcomeWizard( NoticeVO $notice ) {
251
+ $name = $this->getCon()->getHumanName();
252
  $notice->render_data = [
253
  'notice_attributes' => [],
254
  'strings' => [
255
  'dismiss' => __( "I don't need the setup wizard just now", 'wp-simple-firewall' ),
256
+ 'title' => sprintf( __( 'Get started quickly with the %s Setup Wizard', 'wp-simple-firewall' ), $name ),
257
+ 'setup' => sprintf( __( 'The welcome wizard will help you get setup quickly and become familiar with some of the core %s features', 'wp-simple-firewall' ), $name ),
258
+ 'launch' => sprintf( __( "Launch the welcome wizard", 'wp-simple-firewall' ), $name ),
259
  ],
260
  'hrefs' => [
261
  'wizard' => $this->getMod()->getUrl_Wizard( 'welcome' ),
316
 
317
  switch ( $notice->id ) {
318
 
319
+ case 'plugin-too-old':
320
+ $needed = true||$this->isNeeded_PluginTooOld();
321
+ break;
322
+
323
  case 'override-forceoff':
324
  $needed = $oCon->getIfForceOffActive();
325
  break;
350
  }
351
  return $needed;
352
  }
353
+
354
+ private function isNeeded_PluginTooOld() :bool {
355
+ $needed = false;
356
+ $con = $this->getCon();
357
+ if ( Services::WpPlugins()->isUpdateAvailable( $con->getPluginBaseFile() ) ) {
358
+ $versions = Transient::Get( $con->prefix( 'releases' ) );
359
+ if ( !is_array( $versions ) ) {
360
+ $versions = ( new Shield\Utilities\Github\ListTags() )->run( 'FernleafSystems/Shield-Security-for-WordPress' );
361
+ Transient::Set( $con->prefix( 'releases' ), $versions, WEEK_IN_SECONDS );
362
+ }
363
+ array_splice( $versions, array_search( $con->getVersion(), $versions ) );
364
+ $needed = count( array_unique( array_map( function ( $version ) {
365
+ return substr( $version, 0, strrpos( $version, '.' ) );
366
+ }, $versions ) ) ) > 2;
367
+ }
368
+ return $needed;
369
+ }
370
  }
src/lib/src/Modules/Sessions/Processor.php CHANGED
@@ -26,7 +26,9 @@ class Processor extends BaseShield\Processor {
26
  }
27
 
28
  add_filter( 'login_message', [ $this, 'printLinkToAdmin' ] );
 
29
  $this->setupLoginCaptureHooks();
 
30
  }
31
 
32
  protected function captureLogin( \WP_User $user ) {
26
  }
27
 
28
  add_filter( 'login_message', [ $this, 'printLinkToAdmin' ] );
29
+
30
  $this->setupLoginCaptureHooks();
31
+ $this->setToCaptureApplicationLogin( true );
32
  }
33
 
34
  protected function captureLogin( \WP_User $user ) {
src/lib/src/Utilities/Consumer/WpLoginCapture.php CHANGED
@@ -11,6 +11,11 @@ trait WpLoginCapture {
11
  */
12
  private $isLoginCaptured = false;
13
 
 
 
 
 
 
14
  abstract protected function captureLogin( \WP_User $user );
15
 
16
  protected function getLoginPassword() :string {
@@ -25,15 +30,32 @@ trait WpLoginCapture {
25
  return $pass;
26
  }
27
 
 
 
 
 
28
  protected function isLoginCaptured() :bool {
29
  return $this->isLoginCaptured;
30
  }
31
 
 
 
 
 
 
 
 
 
32
  protected function setLoginCaptured( bool $captured = true ) :self {
33
  $this->isLoginCaptured = $captured;
34
  return $this;
35
  }
36
 
 
 
 
 
 
37
  protected function setupLoginCaptureHooks() {
38
  add_action( 'wp_login', [ $this, 'onWpLogin' ], 10, 2 );
39
  if ( !Services::WpUsers()->isProfilePage() ) { // Ignore firing during profile update.
@@ -49,7 +71,7 @@ trait WpLoginCapture {
49
  */
50
  public function onWpSetLoggedInCookie( $cookie, $expire, $expiration, $userID ) {
51
  $user = Services::WpUsers()->getUserById( $userID );
52
- if ( !$this->isLoginCaptured() && $user instanceof \WP_User ) {
53
  $this->setLoginCaptured();
54
  $this->captureLogin( $user );
55
  }
@@ -60,7 +82,7 @@ trait WpLoginCapture {
60
  * @param \WP_User $user
61
  */
62
  public function onWpLogin( $username, $user ) {
63
- if ( !$this->isLoginCaptured() && $user instanceof \WP_User ) {
64
  $this->setLoginCaptured();
65
  $this->captureLogin( $user );
66
  }
11
  */
12
  private $isLoginCaptured = false;
13
 
14
+ /**
15
+ * @var bool
16
+ */
17
+ private $isCaptureApplicationLogin = false;
18
+
19
  abstract protected function captureLogin( \WP_User $user );
20
 
21
  protected function getLoginPassword() :string {
30
  return $pass;
31
  }
32
 
33
+ protected function isCaptureApplicationLogin() :bool {
34
+ return $this->isCaptureApplicationLogin;
35
+ }
36
+
37
  protected function isLoginCaptured() :bool {
38
  return $this->isLoginCaptured;
39
  }
40
 
41
+ /**
42
+ * By default, will only capture logins if it's not an API request, or it's set to capture api requests also.
43
+ * @return bool
44
+ */
45
+ protected function isLoginToBeCaptured() :bool {
46
+ return !Services::WpGeneral()->isApplicationPasswordApiRequest() || $this->isCaptureApplicationLogin();
47
+ }
48
+
49
  protected function setLoginCaptured( bool $captured = true ) :self {
50
  $this->isLoginCaptured = $captured;
51
  return $this;
52
  }
53
 
54
+ protected function setToCaptureApplicationLogin( bool $capture = true ) :self {
55
+ $this->isCaptureApplicationLogin = $capture;
56
+ return $this;
57
+ }
58
+
59
  protected function setupLoginCaptureHooks() {
60
  add_action( 'wp_login', [ $this, 'onWpLogin' ], 10, 2 );
61
  if ( !Services::WpUsers()->isProfilePage() ) { // Ignore firing during profile update.
71
  */
72
  public function onWpSetLoggedInCookie( $cookie, $expire, $expiration, $userID ) {
73
  $user = Services::WpUsers()->getUserById( $userID );
74
+ if ( $this->isLoginToBeCaptured() && !$this->isLoginCaptured() && $user instanceof \WP_User ) {
75
  $this->setLoginCaptured();
76
  $this->captureLogin( $user );
77
  }
82
  * @param \WP_User $user
83
  */
84
  public function onWpLogin( $username, $user ) {
85
+ if ( $this->isLoginToBeCaptured() && !$this->isLoginCaptured() && $user instanceof \WP_User ) {
86
  $this->setLoginCaptured();
87
  $this->captureLogin( $user );
88
  }
src/lib/src/Utilities/Github/ListTags.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\Github;
4
+
5
+ use FernleafSystems\Wordpress\Services\Services;
6
+
7
+ class ListTags {
8
+
9
+ const BASE_URL = 'https://api.github.com/repos/%s/tags';
10
+
11
+ public function run( string $repo ) :array {
12
+ $tags = [];
13
+ $raw = Services::HttpRequest()->getContent( sprintf( self::BASE_URL, $repo ) );
14
+ if ( !empty( $raw ) ) {
15
+ $tags = array_map( function ( $tag ) {
16
+ return $tag[ 'name' ];
17
+ }, json_decode( $raw, true ) );
18
+ }
19
+ return is_array( $tags ) ? $tags : [];
20
+ }
21
+ }
22
+
src/lib/vendor/composer/autoload_classmap.php CHANGED
@@ -52,6 +52,10 @@ return array(
52
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\BuildUsers' => $baseDir . '/src/ChangeTrack/Snapshot/BuildUsers.php',
53
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\Collate' => $baseDir . '/src/ChangeTrack/Snapshot/Collate.php',
54
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\SnapshotsConsumer' => $baseDir . '/src/ChangeTrack/Snapshot/SnapshotsConsumer.php',
 
 
 
 
55
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => $baseDir . '/src/Controller/Controller.php',
56
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\GetAllAvailableLocales' => $baseDir . '/src/Controller/I18n/GetAllAvailableLocales.php',
57
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\LoadTextDomain' => $baseDir . '/src/Controller/I18n/LoadTextDomain.php',
@@ -1484,22 +1488,22 @@ return array(
1484
  'UpdateHelper\\UpdateHelperInterface' => $vendorDir . '/kylekatarnls/update-helper/src/UpdateHelper/UpdateHelperInterface.php',
1485
  'WP_Async_Request' => $vendorDir . '/a5hleyrich/wp-background-processing/classes/wp-async-request.php',
1486
  'WP_Background_Process' => $vendorDir . '/a5hleyrich/wp-background-processing/classes/wp-background-process.php',
1487
- 'ZxcvbnPhp\\Feedback' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Feedback.php',
1488
- 'ZxcvbnPhp\\Matcher' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matcher.php',
1489
- 'ZxcvbnPhp\\Matchers\\Bruteforce' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/Bruteforce.php',
1490
- 'ZxcvbnPhp\\Matchers\\DateMatch' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/DateMatch.php',
1491
- 'ZxcvbnPhp\\Matchers\\DictionaryMatch' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/DictionaryMatch.php',
1492
- 'ZxcvbnPhp\\Matchers\\L33tMatch' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/L33tMatch.php',
1493
- 'ZxcvbnPhp\\Matchers\\Match' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/Match.php',
1494
- 'ZxcvbnPhp\\Matchers\\MatchInterface' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/MatchInterface.php',
1495
- 'ZxcvbnPhp\\Matchers\\RepeatMatch' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/RepeatMatch.php',
1496
- 'ZxcvbnPhp\\Matchers\\ReverseDictionaryMatch' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/ReverseDictionaryMatch.php',
1497
- 'ZxcvbnPhp\\Matchers\\SequenceMatch' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/SequenceMatch.php',
1498
- 'ZxcvbnPhp\\Matchers\\SpatialMatch' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/SpatialMatch.php',
1499
- 'ZxcvbnPhp\\Matchers\\YearMatch' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Matchers/YearMatch.php',
1500
- 'ZxcvbnPhp\\Scorer' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Scorer.php',
1501
- 'ZxcvbnPhp\\TimeEstimator' => $vendorDir . '/mkopinsky/zxcvbn-php/src/TimeEstimator.php',
1502
- 'ZxcvbnPhp\\Zxcvbn' => $vendorDir . '/mkopinsky/zxcvbn-php/src/Zxcvbn.php',
1503
  'u2flib_server\\Error' => $baseDir . '/custom/U2F/Yubico/U2F.php',
1504
  'u2flib_server\\RegisterRequest' => $baseDir . '/custom/U2F/Yubico/U2F.php',
1505
  'u2flib_server\\Registration' => $baseDir . '/custom/U2F/Yubico/U2F.php',
52
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\BuildUsers' => $baseDir . '/src/ChangeTrack/Snapshot/BuildUsers.php',
53
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\Collate' => $baseDir . '/src/ChangeTrack/Snapshot/Collate.php',
54
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\SnapshotsConsumer' => $baseDir . '/src/ChangeTrack/Snapshot/SnapshotsConsumer.php',
55
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\ConfigVO' => $baseDir . '/src/Controller/Config/ConfigVO.php',
56
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\LoadConfig' => $baseDir . '/src/Controller/Config/Ops/LoadConfig.php',
57
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\Read' => $baseDir . '/src/Controller/Config/Ops/Read.php',
58
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\Save' => $baseDir . '/src/Controller/Config/Ops/Save.php',
59
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => $baseDir . '/src/Controller/Controller.php',
60
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\GetAllAvailableLocales' => $baseDir . '/src/Controller/I18n/GetAllAvailableLocales.php',
61
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\LoadTextDomain' => $baseDir . '/src/Controller/I18n/LoadTextDomain.php',
1488
  'UpdateHelper\\UpdateHelperInterface' => $vendorDir . '/kylekatarnls/update-helper/src/UpdateHelper/UpdateHelperInterface.php',
1489
  'WP_Async_Request' => $vendorDir . '/a5hleyrich/wp-background-processing/classes/wp-async-request.php',
1490
  'WP_Background_Process' => $vendorDir . '/a5hleyrich/wp-background-processing/classes/wp-background-process.php',
1491
+ 'ZxcvbnPhp\\Feedback' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Feedback.php',
1492
+ 'ZxcvbnPhp\\Matcher' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matcher.php',
1493
+ 'ZxcvbnPhp\\Matchers\\BaseMatch' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/BaseMatch.php',
1494
+ 'ZxcvbnPhp\\Matchers\\Bruteforce' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/Bruteforce.php',
1495
+ 'ZxcvbnPhp\\Matchers\\DateMatch' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/DateMatch.php',
1496
+ 'ZxcvbnPhp\\Matchers\\DictionaryMatch' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/DictionaryMatch.php',
1497
+ 'ZxcvbnPhp\\Matchers\\L33tMatch' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/L33tMatch.php',
1498
+ 'ZxcvbnPhp\\Matchers\\MatchInterface' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/MatchInterface.php',
1499
+ 'ZxcvbnPhp\\Matchers\\RepeatMatch' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/RepeatMatch.php',
1500
+ 'ZxcvbnPhp\\Matchers\\ReverseDictionaryMatch' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/ReverseDictionaryMatch.php',
1501
+ 'ZxcvbnPhp\\Matchers\\SequenceMatch' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/SequenceMatch.php',
1502
+ 'ZxcvbnPhp\\Matchers\\SpatialMatch' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/SpatialMatch.php',
1503
+ 'ZxcvbnPhp\\Matchers\\YearMatch' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Matchers/YearMatch.php',
1504
+ 'ZxcvbnPhp\\Scorer' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Scorer.php',
1505
+ 'ZxcvbnPhp\\TimeEstimator' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/TimeEstimator.php',
1506
+ 'ZxcvbnPhp\\Zxcvbn' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Zxcvbn.php',
1507
  'u2flib_server\\Error' => $baseDir . '/custom/U2F/Yubico/U2F.php',
1508
  'u2flib_server\\RegisterRequest' => $baseDir . '/custom/U2F/Yubico/U2F.php',
1509
  'u2flib_server\\Registration' => $baseDir . '/custom/U2F/Yubico/U2F.php',
src/lib/vendor/composer/autoload_psr4.php CHANGED
@@ -6,7 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
- 'ZxcvbnPhp\\' => array($vendorDir . '/mkopinsky/zxcvbn-php/src'),
10
  'Twig\\' => array($vendorDir . '/twig/twig/src'),
11
  'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
12
  'Symfony\\Polyfill\\Iconv\\' => array($vendorDir . '/symfony/polyfill-iconv'),
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
+ 'ZxcvbnPhp\\' => array($vendorDir . '/fernleafsystems/zxcvbn-php/src'),
10
  'Twig\\' => array($vendorDir . '/twig/twig/src'),
11
  'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
12
  'Symfony\\Polyfill\\Iconv\\' => array($vendorDir . '/symfony/polyfill-iconv'),
src/lib/vendor/composer/autoload_static.php CHANGED
@@ -67,7 +67,7 @@ class ComposerStaticInit0b573d8879ea3b08a114d68dbb7a4533
67
  public static $prefixDirsPsr4 = array (
68
  'ZxcvbnPhp\\' =>
69
  array (
70
- 0 => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src',
71
  ),
72
  'Twig\\' =>
73
  array (
@@ -219,6 +219,10 @@ class ComposerStaticInit0b573d8879ea3b08a114d68dbb7a4533
219
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\BuildUsers' => __DIR__ . '/../..' . '/src/ChangeTrack/Snapshot/BuildUsers.php',
220
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\Collate' => __DIR__ . '/../..' . '/src/ChangeTrack/Snapshot/Collate.php',
221
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\SnapshotsConsumer' => __DIR__ . '/../..' . '/src/ChangeTrack/Snapshot/SnapshotsConsumer.php',
 
 
 
 
222
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => __DIR__ . '/../..' . '/src/Controller/Controller.php',
223
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\GetAllAvailableLocales' => __DIR__ . '/../..' . '/src/Controller/I18n/GetAllAvailableLocales.php',
224
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\LoadTextDomain' => __DIR__ . '/../..' . '/src/Controller/I18n/LoadTextDomain.php',
@@ -1651,22 +1655,22 @@ class ComposerStaticInit0b573d8879ea3b08a114d68dbb7a4533
1651
  'UpdateHelper\\UpdateHelperInterface' => __DIR__ . '/..' . '/kylekatarnls/update-helper/src/UpdateHelper/UpdateHelperInterface.php',
1652
  'WP_Async_Request' => __DIR__ . '/..' . '/a5hleyrich/wp-background-processing/classes/wp-async-request.php',
1653
  'WP_Background_Process' => __DIR__ . '/..' . '/a5hleyrich/wp-background-processing/classes/wp-background-process.php',
1654
- 'ZxcvbnPhp\\Feedback' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Feedback.php',
1655
- 'ZxcvbnPhp\\Matcher' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matcher.php',
1656
- 'ZxcvbnPhp\\Matchers\\Bruteforce' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/Bruteforce.php',
1657
- 'ZxcvbnPhp\\Matchers\\DateMatch' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/DateMatch.php',
1658
- 'ZxcvbnPhp\\Matchers\\DictionaryMatch' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/DictionaryMatch.php',
1659
- 'ZxcvbnPhp\\Matchers\\L33tMatch' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/L33tMatch.php',
1660
- 'ZxcvbnPhp\\Matchers\\Match' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/Match.php',
1661
- 'ZxcvbnPhp\\Matchers\\MatchInterface' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/MatchInterface.php',
1662
- 'ZxcvbnPhp\\Matchers\\RepeatMatch' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/RepeatMatch.php',
1663
- 'ZxcvbnPhp\\Matchers\\ReverseDictionaryMatch' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/ReverseDictionaryMatch.php',
1664
- 'ZxcvbnPhp\\Matchers\\SequenceMatch' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/SequenceMatch.php',
1665
- 'ZxcvbnPhp\\Matchers\\SpatialMatch' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/SpatialMatch.php',
1666
- 'ZxcvbnPhp\\Matchers\\YearMatch' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Matchers/YearMatch.php',
1667
- 'ZxcvbnPhp\\Scorer' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Scorer.php',
1668
- 'ZxcvbnPhp\\TimeEstimator' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/TimeEstimator.php',
1669
- 'ZxcvbnPhp\\Zxcvbn' => __DIR__ . '/..' . '/mkopinsky/zxcvbn-php/src/Zxcvbn.php',
1670
  'u2flib_server\\Error' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
1671
  'u2flib_server\\RegisterRequest' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
1672
  'u2flib_server\\Registration' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
67
  public static $prefixDirsPsr4 = array (
68
  'ZxcvbnPhp\\' =>
69
  array (
70
+ 0 => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src',
71
  ),
72
  'Twig\\' =>
73
  array (
219
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\BuildUsers' => __DIR__ . '/../..' . '/src/ChangeTrack/Snapshot/BuildUsers.php',
220
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\Collate' => __DIR__ . '/../..' . '/src/ChangeTrack/Snapshot/Collate.php',
221
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\SnapshotsConsumer' => __DIR__ . '/../..' . '/src/ChangeTrack/Snapshot/SnapshotsConsumer.php',
222
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\ConfigVO' => __DIR__ . '/../..' . '/src/Controller/Config/ConfigVO.php',
223
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\LoadConfig' => __DIR__ . '/../..' . '/src/Controller/Config/Ops/LoadConfig.php',
224
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\Read' => __DIR__ . '/../..' . '/src/Controller/Config/Ops/Read.php',
225
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\Save' => __DIR__ . '/../..' . '/src/Controller/Config/Ops/Save.php',
226
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => __DIR__ . '/../..' . '/src/Controller/Controller.php',
227
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\GetAllAvailableLocales' => __DIR__ . '/../..' . '/src/Controller/I18n/GetAllAvailableLocales.php',
228
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\LoadTextDomain' => __DIR__ . '/../..' . '/src/Controller/I18n/LoadTextDomain.php',
1655
  'UpdateHelper\\UpdateHelperInterface' => __DIR__ . '/..' . '/kylekatarnls/update-helper/src/UpdateHelper/UpdateHelperInterface.php',
1656
  'WP_Async_Request' => __DIR__ . '/..' . '/a5hleyrich/wp-background-processing/classes/wp-async-request.php',
1657
  'WP_Background_Process' => __DIR__ . '/..' . '/a5hleyrich/wp-background-processing/classes/wp-background-process.php',
1658
+ 'ZxcvbnPhp\\Feedback' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Feedback.php',
1659
+ 'ZxcvbnPhp\\Matcher' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matcher.php',
1660
+ 'ZxcvbnPhp\\Matchers\\BaseMatch' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/BaseMatch.php',
1661
+ 'ZxcvbnPhp\\Matchers\\Bruteforce' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/Bruteforce.php',
1662
+ 'ZxcvbnPhp\\Matchers\\DateMatch' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/DateMatch.php',
1663
+ 'ZxcvbnPhp\\Matchers\\DictionaryMatch' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/DictionaryMatch.php',
1664
+ 'ZxcvbnPhp\\Matchers\\L33tMatch' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/L33tMatch.php',
1665
+ 'ZxcvbnPhp\\Matchers\\MatchInterface' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/MatchInterface.php',
1666
+ 'ZxcvbnPhp\\Matchers\\RepeatMatch' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/RepeatMatch.php',
1667
+ 'ZxcvbnPhp\\Matchers\\ReverseDictionaryMatch' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/ReverseDictionaryMatch.php',
1668
+ 'ZxcvbnPhp\\Matchers\\SequenceMatch' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/SequenceMatch.php',
1669
+ 'ZxcvbnPhp\\Matchers\\SpatialMatch' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/SpatialMatch.php',
1670
+ 'ZxcvbnPhp\\Matchers\\YearMatch' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Matchers/YearMatch.php',
1671
+ 'ZxcvbnPhp\\Scorer' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Scorer.php',
1672
+ 'ZxcvbnPhp\\TimeEstimator' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/TimeEstimator.php',
1673
+ 'ZxcvbnPhp\\Zxcvbn' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Zxcvbn.php',
1674
  'u2flib_server\\Error' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
1675
  'u2flib_server\\RegisterRequest' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
1676
  'u2flib_server\\Registration' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
src/lib/vendor/fernleafsystems/wordpress-services/src/Core/General.php CHANGED
@@ -418,6 +418,11 @@ class General {
418
  return defined( 'COOKIEPATH' ) ? COOKIEPATH : '/';
419
  }
420
 
 
 
 
 
 
421
  public function isAjax() :bool {
422
  return function_exists( 'wp_doing_ajax' ) ? wp_doing_ajax() : defined( 'DOING_AJAX' ) && DOING_AJAX;
423
  }
418
  return defined( 'COOKIEPATH' ) ? COOKIEPATH : '/';
419
  }
420
 
421
+ public function isApplicationPasswordApiRequest() :bool {
422
+ return (bool)apply_filters( 'application_password_is_api_request',
423
+ $this->isXmlrpc() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) );
424
+ }
425
+
426
  public function isAjax() :bool {
427
  return function_exists( 'wp_doing_ajax' ) ? wp_doing_ajax() : defined( 'DOING_AJAX' ) && DOING_AJAX;
428
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Core/Users.php CHANGED
@@ -2,40 +2,30 @@
2
 
3
  namespace FernleafSystems\Wordpress\Services\Core;
4
 
5
- use FernleafSystems\Wordpress\Services\Utilities\PluginUserMeta;
6
  use FernleafSystems\Wordpress\Services\Services;
 
7
 
8
- /**
9
- */
10
  class Users {
11
 
12
  /**
13
- * @param string $sKey
14
- * @param int $nUserId -user ID
15
  * @return bool
16
  */
17
- public function deleteUserMeta( $sKey, $nUserId = null ) {
18
- if ( empty( $nUserId ) ) {
19
- $nUserId = $this->getCurrentWpUserId();
20
  }
21
- elseif ( $nUserId instanceof \WP_User ) {
22
- $nUserId = $nUserId->ID;
23
  }
24
 
25
- $bSuccess = false;
26
- if ( $nUserId > 0 ) {
27
- $bSuccess = delete_user_meta( $nUserId, $sKey );
28
- }
29
- return $bSuccess;
30
  }
31
 
32
- /**
33
- * @param string $sUsernameOrEmail
34
- * @return bool
35
- */
36
- public function exists( $sUsernameOrEmail ) {
37
- return ( $this->getUserByEmail( $sUsernameOrEmail ) instanceof \WP_User )
38
- || ( $this->getUserByUsername( $sUsernameOrEmail ) instanceof \WP_User );
39
  }
40
 
41
  /**
@@ -47,26 +37,21 @@ class Users {
47
  }
48
 
49
  /**
50
- * @param \WP_User $oUser
51
  * @return string
52
  */
53
- public function getAdminUrl_ProfileEdit( $oUser = null ) {
54
- if ( $oUser instanceof \WP_User ) {
55
- $sPath = 'user-edit.php?user_id='.$oUser->ID;
56
- }
57
- else {
58
- $sPath = 'profile.php';
59
- }
60
- return Services::WpGeneral()->getAdminUrl( $sPath );
61
  }
62
 
63
  /**
64
- * @param array $aArgs
65
  * @return \WP_User[]
66
  */
67
- public function getAllUsers( $aArgs = [] ) {
68
- $aArgs = wp_parse_args(
69
- $aArgs,
70
  [
71
  'blog_id' => 0,
72
  // 'fields' => array(
@@ -77,16 +62,13 @@ class Users {
77
  // )
78
  ]
79
  );
80
- return function_exists( 'get_users' ) ? get_users( $aArgs ) : [];
81
  }
82
 
83
- /**
84
- * @return array
85
- */
86
- public function getAllUserLoginUsernames() {
87
  return array_map(
88
- function ( $oUser ) {
89
- return $oUser->user_login;
90
  },
91
  $this->getAllUsers( [ 'fields' => [ 'user_login' ] ] )
92
  );
@@ -96,14 +78,11 @@ class Users {
96
  * @return int
97
  */
98
  public function getCurrentUserLevel() {
99
- $oUser = $this->getCurrentWpUser();
100
- return ( $oUser instanceof \WP_User ) ? $oUser->get( 'user_level' ) : -1;
101
  }
102
 
103
- /**
104
- * @return array
105
- */
106
- public function getLevelToRoleMap() {
107
  return [
108
  0 => 'subscriber',
109
  1 => 'contributor',
@@ -122,26 +101,22 @@ class Users {
122
  return $bSlugsOnly ? array_keys( get_editable_roles() ) : get_editable_roles();
123
  }
124
 
125
- /**
126
- * @return bool
127
- */
128
- public function canSaveMeta() {
129
- $bCanMeta = false;
130
  try {
131
  if ( $this->isUserLoggedIn() ) {
132
- $sKey = 'icwp-flag-can-store-user-meta';
133
- $sMeta = $this->getUserMeta( $sKey );
134
- if ( $sMeta == 'icwp' ) {
135
- $bCanMeta = true;
136
  }
137
  else {
138
- $bCanMeta = $this->updateUserMeta( $sKey, 'icwp' );
139
  }
140
  }
141
  }
142
- catch ( \Exception $oE ) {
143
  }
144
- return $bCanMeta;
145
  }
146
 
147
  /**
@@ -166,128 +141,123 @@ class Users {
166
  }
167
 
168
  /**
169
- * @param string $sEmail
170
  * @return \WP_User|null
171
  */
172
- public function getUserByEmail( $sEmail ) {
173
- return $this->getUserBy( 'email', $sEmail );
174
  }
175
 
176
  /**
177
- * @param int $nId
178
  * @return \WP_User|null
179
  */
180
- public function getUserById( $nId ) {
181
- return $this->getUserBy( 'id', $nId );
182
  }
183
 
184
  /**
185
- * @param $sUsername
186
  * @return null|\WP_User
187
  */
188
- public function getUserByUsername( $sUsername ) {
189
- return $this->getUserBy( 'login', $sUsername );
190
  }
191
 
192
  /**
193
- * @param string $sKey
194
- * @param mixed $mValue
195
  * @return null|\WP_User
196
  */
197
- public function getUserBy( $sKey, $mValue ) {
198
- $oU = function_exists( 'get_user_by' ) ? get_user_by( $sKey, $mValue ) : null;
199
  return empty( $oU ) ? null : $oU;
200
  }
201
 
202
  /**
203
- * @param string $sKey should be already prefixed
204
- * @param int|null $nUserId - if omitted get for current user
205
  * @return false|string
206
  */
207
- public function getUserMeta( $sKey, $nUserId = null ) {
208
- if ( empty( $nUserId ) ) {
209
- $nUserId = $this->getCurrentWpUserId();
210
  }
211
- elseif ( $nUserId instanceof \WP_User ) {
212
- $nUserId = $nUserId->ID;
213
  }
214
 
215
  $mResult = false;
216
- if ( $nUserId > 0 ) {
217
- $mResult = get_user_meta( $nUserId, $sKey, true );
218
  }
219
  return $mResult;
220
  }
221
 
222
  /**
223
- * @param \WP_User $oUser
224
  * @return string|null
225
  * @see wp-login.php
226
  */
227
- public function getPasswordResetUrl( $oUser ) {
228
- $sUrl = null;
229
 
230
- $sResetKey = get_password_reset_key( $oUser );
231
- if ( !is_wp_error( $sResetKey ) ) {
232
- $sUrl = add_query_arg(
233
  [
234
  'action' => 'rp',
235
- 'key' => $sResetKey,
236
- 'login' => $oUser->user_login,
237
  ],
238
  wp_login_url()
239
  );
240
  }
241
 
242
- return $sUrl;
243
  }
244
 
245
  /**
246
- * @param \WP_User|null $oUser
247
  * @return bool
248
  */
249
- public function isUserAdmin( $oUser = null ) {
250
- if ( empty( $oUser ) ) {
251
- $bIsAdmin = $this->isUserLoggedIn() && current_user_can( 'manage_options' );
252
- }
253
- else {
254
- $bIsAdmin = user_can( $oUser, 'manage_options' );
255
  }
256
- return $bIsAdmin;
257
  }
258
 
259
- /**
260
- * @return bool
261
- */
262
- public function isProfilePage() {
263
  return defined( 'IS_PROFILE_PAGE' ) && IS_PROFILE_PAGE;
264
  }
265
 
266
- /**
267
- * @return bool
268
- */
269
- public function isUserLoggedIn() {
270
  return function_exists( 'is_user_logged_in' ) && is_user_logged_in();
271
  }
272
 
 
 
 
 
273
  /**
274
- * @param string $sPrefix
275
- * @param int $nUserId
276
  * @return PluginUserMeta
277
  * @throws \Exception
278
  */
279
- public function metaVoForUser( $sPrefix, $nUserId = null ) {
280
- return PluginUserMeta::Load( $sPrefix, $nUserId );
281
  }
282
 
283
  /**
284
  * Fires the WordPress logout functions. If $bQuiet is true, it'll manually
285
  * call the WordPress logout code, so as not to fire any other logout actions
286
  * We might want to be "quiet" so as not to fire out own action hooks.
287
- * @param bool $bQuiet
288
  */
289
- public function logoutUser( $bQuiet = false ) {
290
- if ( $bQuiet ) {
291
  wp_destroy_current_session();
292
  wp_clear_auth_cookie();
293
  }
@@ -298,39 +268,34 @@ class Users {
298
 
299
  /**
300
  * Updates the user meta data for the current (or supplied user ID)
301
- * @param string $sKey
302
  * @param mixed $mValue
303
- * @param \WP_User|int $nUserId -user ID
304
  * @return bool
305
  */
306
- public function updateUserMeta( $sKey, $mValue, $nUserId = null ) {
307
- if ( empty( $nUserId ) ) {
308
- $nUserId = $this->getCurrentWpUserId();
309
- }
310
- elseif ( $nUserId instanceof \WP_User ) {
311
- $nUserId = $nUserId->ID;
312
  }
313
-
314
- $bSuccess = false;
315
- if ( $nUserId > 0 ) {
316
- $bSuccess = update_user_meta( $nUserId, $sKey, $mValue );
317
  }
318
- return $bSuccess;
319
  }
320
 
321
  /**
322
- * @param string $sUsername
323
  * @return bool
324
  */
325
- public function setUserLoggedIn( $sUsername ) {
326
- $oUser = $this->getUserByUsername( $sUsername );
327
- $bSuccess = $oUser instanceof \WP_User;
328
- if ( $bSuccess ) {
329
  wp_clear_auth_cookie();
330
- wp_set_current_user( $oUser->ID, $oUser->user_login );
331
- wp_set_auth_cookie( $oUser->ID, true );
332
- do_action( 'wp_login', $oUser->user_login, $oUser );
333
  }
334
- return $bSuccess;
335
  }
336
  }
2
 
3
  namespace FernleafSystems\Wordpress\Services\Core;
4
 
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
+ use FernleafSystems\Wordpress\Services\Utilities\PluginUserMeta;
7
 
 
 
8
  class Users {
9
 
10
  /**
11
+ * @param string $key
12
+ * @param \WP_User|int $userID -user ID
13
  * @return bool
14
  */
15
+ public function deleteUserMeta( string $key, $userID = null ) {
16
+ if ( empty( $userID ) ) {
17
+ $userID = $this->getCurrentWpUserId();
18
  }
19
+ elseif ( $userID instanceof \WP_User ) {
20
+ $userID = $userID->ID;
21
  }
22
 
23
+ return $userID > 0 ? delete_user_meta( $userID, $key ) : false;
 
 
 
 
24
  }
25
 
26
+ public function exists( string $usernameOrEmail ) :bool {
27
+ return ( $this->getUserByEmail( $usernameOrEmail ) instanceof \WP_User )
28
+ || ( $this->getUserByUsername( $usernameOrEmail ) instanceof \WP_User );
 
 
 
 
29
  }
30
 
31
  /**
37
  }
38
 
39
  /**
40
+ * @param \WP_User $u
41
  * @return string
42
  */
43
+ public function getAdminUrl_ProfileEdit( $u = null ) {
44
+ $path = $u instanceof \WP_User ? 'user-edit.php?user_id='.$u->ID : 'profile.php';
45
+ return Services::WpGeneral()->getAdminUrl( $path );
 
 
 
 
 
46
  }
47
 
48
  /**
49
+ * @param array $args
50
  * @return \WP_User[]
51
  */
52
+ public function getAllUsers( $args = [] ) {
53
+ $args = wp_parse_args(
54
+ $args,
55
  [
56
  'blog_id' => 0,
57
  // 'fields' => array(
62
  // )
63
  ]
64
  );
65
+ return function_exists( 'get_users' ) ? get_users( $args ) : [];
66
  }
67
 
68
+ public function getAllUserLoginUsernames() :array {
 
 
 
69
  return array_map(
70
+ function ( $user ) {
71
+ return $user->user_login;
72
  },
73
  $this->getAllUsers( [ 'fields' => [ 'user_login' ] ] )
74
  );
78
  * @return int
79
  */
80
  public function getCurrentUserLevel() {
81
+ $user = $this->getCurrentWpUser();
82
+ return ( $user instanceof \WP_User ) ? $user->get( 'user_level' ) : -1;
83
  }
84
 
85
+ public function getLevelToRoleMap() :array {
 
 
 
86
  return [
87
  0 => 'subscriber',
88
  1 => 'contributor',
101
  return $bSlugsOnly ? array_keys( get_editable_roles() ) : get_editable_roles();
102
  }
103
 
104
+ public function canSaveMeta() :bool {
105
+ $can = false;
 
 
 
106
  try {
107
  if ( $this->isUserLoggedIn() ) {
108
+ $key = 'icwp-flag-can-store-user-meta';
109
+ if ( $this->getUserMeta( $key ) == 'icwp' ) {
110
+ $can = true;
 
111
  }
112
  else {
113
+ $can = (bool)$this->updateUserMeta( $key, 'icwp' );
114
  }
115
  }
116
  }
117
+ catch ( \Exception $e ) {
118
  }
119
+ return $can;
120
  }
121
 
122
  /**
141
  }
142
 
143
  /**
144
+ * @param string $email
145
  * @return \WP_User|null
146
  */
147
+ public function getUserByEmail( string $email ) {
148
+ return $this->getUserBy( 'email', $email );
149
  }
150
 
151
  /**
152
+ * @param int $id
153
  * @return \WP_User|null
154
  */
155
+ public function getUserById( $id ) {
156
+ return $this->getUserBy( 'id', $id );
157
  }
158
 
159
  /**
160
+ * @param $username
161
  * @return null|\WP_User
162
  */
163
+ public function getUserByUsername( string $username ) {
164
+ return $this->getUserBy( 'login', $username );
165
  }
166
 
167
  /**
168
+ * @param string $byKey
169
+ * @param mixed $value
170
  * @return null|\WP_User
171
  */
172
+ public function getUserBy( $byKey, $value ) {
173
+ $oU = function_exists( 'get_user_by' ) ? get_user_by( $byKey, $value ) : null;
174
  return empty( $oU ) ? null : $oU;
175
  }
176
 
177
  /**
178
+ * @param string $key should be already prefixed
179
+ * @param int|null $userID - if omitted get for current user
180
  * @return false|string
181
  */
182
+ public function getUserMeta( $key, $userID = null ) {
183
+ if ( empty( $userID ) ) {
184
+ $userID = $this->getCurrentWpUserId();
185
  }
186
+ elseif ( $userID instanceof \WP_User ) {
187
+ $userID = $userID->ID;
188
  }
189
 
190
  $mResult = false;
191
+ if ( $userID > 0 ) {
192
+ $mResult = get_user_meta( $userID, $key, true );
193
  }
194
  return $mResult;
195
  }
196
 
197
  /**
198
+ * @param \WP_User $user
199
  * @return string|null
200
  * @see wp-login.php
201
  */
202
+ public function getPasswordResetUrl( $user ) {
203
+ $url = null;
204
 
205
+ $key = get_password_reset_key( $user );
206
+ if ( !is_wp_error( $key ) ) {
207
+ $url = add_query_arg(
208
  [
209
  'action' => 'rp',
210
+ 'key' => $key,
211
+ 'login' => $user->user_login,
212
  ],
213
  wp_login_url()
214
  );
215
  }
216
 
217
+ return $url;
218
  }
219
 
220
  /**
221
+ * @param \WP_User|null $user
222
  * @return bool
223
  */
224
+ public function isUserAdmin( $user = null ) {
225
+ if ( empty( $user ) ) {
226
+ $user = $this->getCurrentWpUser();
 
 
 
227
  }
228
+ return user_can( $user, 'manage_options' );
229
  }
230
 
231
+ public function isProfilePage() :bool {
 
 
 
232
  return defined( 'IS_PROFILE_PAGE' ) && IS_PROFILE_PAGE;
233
  }
234
 
235
+ public function isUserLoggedIn() :bool {
 
 
 
236
  return function_exists( 'is_user_logged_in' ) && is_user_logged_in();
237
  }
238
 
239
+ public function isAppPasswordAuth() :bool {
240
+ return did_action( 'application_password_did_authenticate' ) > 0;
241
+ }
242
+
243
  /**
244
+ * @param string $prefix
245
+ * @param int $userID
246
  * @return PluginUserMeta
247
  * @throws \Exception
248
  */
249
+ public function metaVoForUser( string $prefix, $userID = null ) {
250
+ return PluginUserMeta::Load( $prefix, $userID );
251
  }
252
 
253
  /**
254
  * Fires the WordPress logout functions. If $bQuiet is true, it'll manually
255
  * call the WordPress logout code, so as not to fire any other logout actions
256
  * We might want to be "quiet" so as not to fire out own action hooks.
257
+ * @param bool $doQuiet
258
  */
259
+ public function logoutUser( $doQuiet = false ) {
260
+ if ( $doQuiet ) {
261
  wp_destroy_current_session();
262
  wp_clear_auth_cookie();
263
  }
268
 
269
  /**
270
  * Updates the user meta data for the current (or supplied user ID)
271
+ * @param string $key
272
  * @param mixed $mValue
273
+ * @param \WP_User|int $userID -user ID
274
  * @return bool
275
  */
276
+ public function updateUserMeta( string $key, $mValue, $userID = null ) {
277
+ if ( empty( $userID ) ) {
278
+ $userID = $this->getCurrentWpUserId();
 
 
 
279
  }
280
+ elseif ( $userID instanceof \WP_User ) {
281
+ $userID = $userID->ID;
 
 
282
  }
283
+ return $userID > 0 ? update_user_meta( $userID, $key, $mValue ) : false;
284
  }
285
 
286
  /**
287
+ * @param string $username
288
  * @return bool
289
  */
290
+ public function setUserLoggedIn( string $username ) {
291
+ $user = $this->getUserByUsername( $username );
292
+ $success = $user instanceof \WP_User;
293
+ if ( $success ) {
294
  wp_clear_auth_cookie();
295
+ wp_set_current_user( $user->ID, $user->user_login );
296
+ wp_set_auth_cookie( $user->ID, true );
297
+ do_action( 'wp_login', $user->user_login, $user );
298
  }
299
+ return $success;
300
  }
301
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Net/IpIdentify.php CHANGED
@@ -12,14 +12,15 @@ class IpIdentify {
12
  const APPLE = 'apple';
13
  const BAIDU = 'baidu';
14
  const BING = 'bing';
15
- const BLOGVAULT = 'blogvault';
16
  const CLOUDFLARE = 'cloudflare';
17
  const DUCKDUCKGO = 'duckduckgo';
18
  const GOOGLE = 'google';
 
19
  const HUAWEI = 'huawei';
20
  const ICONTROLWP = 'icontrolwp';
21
  const MANAGEWP = 'managewp';
22
  const NODEPING = 'nodeping';
 
23
  const PINGDOM = 'pingdom';
24
  const STATUSCAKE = 'statuscake';
25
  const SEMRUSH = 'semrush';
@@ -67,9 +68,6 @@ class IpIdentify {
67
  elseif ( $srvProviders->isIp_BingBot( $this->ip, $this->agent ) ) {
68
  $is = self::BING;
69
  }
70
- elseif ( $srvProviders->isIp_BlogVault( $this->ip ) ) {
71
- $is = self::BLOGVAULT;
72
- }
73
  elseif ( $srvProviders->isIp_Cloudflare( $this->ip ) ) {
74
  $is = self::CLOUDFLARE;
75
  }
@@ -79,6 +77,9 @@ class IpIdentify {
79
  elseif ( $srvProviders->isIp_GoogleBot( $this->ip, $this->agent ) ) {
80
  $is = self::GOOGLE;
81
  }
 
 
 
82
  elseif ( $srvProviders->isIp_HuaweiBot( $this->ip, $this->agent ) ) {
83
  $is = self::HUAWEI;
84
  }
@@ -91,6 +92,9 @@ class IpIdentify {
91
  elseif ( $srvProviders->isIpInCollection( $this->ip, $srvProviders->getIps_NodePing() ) ) {
92
  $is = self::NODEPING;
93
  }
 
 
 
94
  elseif ( $srvProviders->isIp_Pingdom( $this->ip, $this->agent ) ) {
95
  $is = self::PINGDOM;
96
  }
@@ -130,13 +134,14 @@ class IpIdentify {
130
  self::APPLE => 'AppleBot',
131
  self::BAIDU => 'BaiduBot',
132
  self::BING => 'BingBot',
133
- self::BLOGVAULT => 'BlogVault',
134
  self::CLOUDFLARE => 'CloudFlare',
135
  self::DUCKDUCKGO => 'DuckDuckGoBot',
136
  self::GOOGLE => 'GoogleBot',
137
  self::HUAWEI => 'Huawei/PetalBot',
 
138
  self::ICONTROLWP => 'iControlWP',
139
  self::MANAGEWP => 'ManageWP',
 
140
  self::PINGDOM => 'Pingdom',
141
  self::SEMRUSH => 'SEMRush',
142
  self::STATUSCAKE => 'StatusCake',
12
  const APPLE = 'apple';
13
  const BAIDU = 'baidu';
14
  const BING = 'bing';
 
15
  const CLOUDFLARE = 'cloudflare';
16
  const DUCKDUCKGO = 'duckduckgo';
17
  const GOOGLE = 'google';
18
+ const GTMETRIX = 'gtmetrix';
19
  const HUAWEI = 'huawei';
20
  const ICONTROLWP = 'icontrolwp';
21
  const MANAGEWP = 'managewp';
22
  const NODEPING = 'nodeping';
23
+ const PAYPAL = 'paypal';
24
  const PINGDOM = 'pingdom';
25
  const STATUSCAKE = 'statuscake';
26
  const SEMRUSH = 'semrush';
68
  elseif ( $srvProviders->isIp_BingBot( $this->ip, $this->agent ) ) {
69
  $is = self::BING;
70
  }
 
 
 
71
  elseif ( $srvProviders->isIp_Cloudflare( $this->ip ) ) {
72
  $is = self::CLOUDFLARE;
73
  }
77
  elseif ( $srvProviders->isIp_GoogleBot( $this->ip, $this->agent ) ) {
78
  $is = self::GOOGLE;
79
  }
80
+ elseif ( $srvProviders->isIpInCollection( $this->ip, $srvProviders->getIpsForSlug( self::GTMETRIX ) ) ) {
81
+ $is = self::GTMETRIX;
82
+ }
83
  elseif ( $srvProviders->isIp_HuaweiBot( $this->ip, $this->agent ) ) {
84
  $is = self::HUAWEI;
85
  }
92
  elseif ( $srvProviders->isIpInCollection( $this->ip, $srvProviders->getIps_NodePing() ) ) {
93
  $is = self::NODEPING;
94
  }
95
+ elseif ( $srvProviders->isIp_PayPal( $this->ip ) ) {
96
+ $is = self::PAYPAL;
97
+ }
98
  elseif ( $srvProviders->isIp_Pingdom( $this->ip, $this->agent ) ) {
99
  $is = self::PINGDOM;
100
  }
134
  self::APPLE => 'AppleBot',
135
  self::BAIDU => 'BaiduBot',
136
  self::BING => 'BingBot',
 
137
  self::CLOUDFLARE => 'CloudFlare',
138
  self::DUCKDUCKGO => 'DuckDuckGoBot',
139
  self::GOOGLE => 'GoogleBot',
140
  self::HUAWEI => 'Huawei/PetalBot',
141
+ self::GTMETRIX => 'GTMetrix',
142
  self::ICONTROLWP => 'iControlWP',
143
  self::MANAGEWP => 'ManageWP',
144
+ self::PAYPAL => 'PayPal',
145
  self::PINGDOM => 'Pingdom',
146
  self::SEMRUSH => 'SEMRush',
147
  self::STATUSCAKE => 'StatusCake',
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/ServiceProviders.php CHANGED
@@ -229,24 +229,12 @@ class ServiceProviders {
229
 
230
  /**
231
  * @param string $ip
 
232
  * @return bool
 
233
  */
234
- public function isIp_BlogVault( $ip ) :bool {
235
- $WP = Services::WpGeneral();
236
-
237
- $storeKey = $this->getPrefixedStoreKey( 'serviceips_blogvault' );
238
-
239
- $ips = $WP->getTransient( $storeKey );
240
- if ( !is_array( $ips ) ) {
241
- $ips = [];
242
- }
243
-
244
- if ( !in_array( $ip, $ips ) && $this->isIpOfBot( [], '#blogvault\.net#', $ip, null ) ) {
245
- $ips[] = $ip;
246
- $WP->setTransient( $storeKey, $ips, WEEK_IN_SECONDS*4 );
247
- }
248
-
249
- return in_array( $ip, $ips );
250
  }
251
 
252
  /**
@@ -270,14 +258,13 @@ class ServiceProviders {
270
 
271
  /**
272
  * @param string $ip
273
- * @param string[][] $aSet
274
  * @return bool
275
  */
276
- public function isIpInCollection( $ip, $aSet ) :bool {
277
  try {
278
- $oIpUtil = Services::IP();
279
- $version = $oIpUtil->getIpVersion( $ip );
280
- $exists = $version !== false && $oIpUtil->checkIp( $ip, $aSet[ $version ] );
281
  }
282
  catch ( \Exception $e ) {
283
  $exists = false;
@@ -286,14 +273,14 @@ class ServiceProviders {
286
  }
287
 
288
  /**
289
- * @param string $sIp
290
- * @param string $sAgent
291
  * @return bool
292
  */
293
- public function isIp_iControlWP( $sIp, $sAgent = null ) { //TODO: Agent
294
  $bIsBot = false;
295
- if ( is_null( $sAgent ) || stripos( $sAgent, 'iControlWPApp' ) !== false ) {
296
- $bIsBot = $this->isIpInCollection( $sIp, $this->getIpsForSlug( 'icontrolwp' ) );
297
  }
298
  return $bIsBot;
299
  }
@@ -325,28 +312,36 @@ class ServiceProviders {
325
  * @param string $ip
326
  * @return bool
327
  */
328
- public function isIp_ManageWP( $ip ) {
329
  return $this->isIpInCollection( $ip, $this->getIpsForSlug( 'managewp' ) );
330
  }
331
 
 
 
 
 
 
 
 
 
332
  /**
333
  * @param string $ip
334
  * @param string $agent
335
  * @return bool
336
  */
337
- public function isIp_Pingdom( $ip, $agent ) {
338
  return ( stripos( $agent, 'pingdom.com' ) !== false )
339
  && $this->isIpInCollection( $ip, $this->getIpsForSlug( 'pingdom' ) );
340
  }
341
 
342
  /**
343
- * @param string $sIp
344
- * @param string $sAgent
345
  * @return bool
346
  */
347
- public function isIp_Stripe( $sIp, $sAgent ) {
348
- return ( stripos( $sAgent, 'Stripe/' ) !== false )
349
- && $this->isIpInCollection( $sIp, $this->getIpsForSlug( 'stripe' ) );
350
  }
351
 
352
  /**
@@ -382,7 +377,7 @@ class ServiceProviders {
382
  }
383
 
384
  public function isIp_UptimeRobot( $ip, $agent ) :bool {
385
- return ( empty( $agent ) || ( stripos( $agent, 'StatusCake' ) !== false ) )
386
  && $this->isIpInCollection( $ip, $this->getIpsForSlug( 'uptimerobot' ) );
387
  }
388
 
229
 
230
  /**
231
  * @param string $ip
232
+ * @param string $agent
233
  * @return bool
234
+ * @deprecated 2.10.1
235
  */
236
+ public function isIp_BlogVault( $ip, $agent ) :bool {
237
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  }
239
 
240
  /**
258
 
259
  /**
260
  * @param string $ip
261
+ * @param string[][] $set
262
  * @return bool
263
  */
264
+ public function isIpInCollection( $ip, array $set ) :bool {
265
  try {
266
+ $version = Services::IP()->getIpVersion( $ip );
267
+ $exists = $version !== false && Services::IP()->checkIp( $ip, $set[ $version ] );
 
268
  }
269
  catch ( \Exception $e ) {
270
  $exists = false;
273
  }
274
 
275
  /**
276
+ * @param string $ip
277
+ * @param string $agent
278
  * @return bool
279
  */
280
+ public function isIp_iControlWP( string $ip, $agent = null ) :bool { //TODO: Agent
281
  $bIsBot = false;
282
+ if ( is_null( $agent ) || stripos( $agent, 'iControlWPApp' ) !== false ) {
283
+ $bIsBot = $this->isIpInCollection( $ip, $this->getIpsForSlug( 'icontrolwp' ) );
284
  }
285
  return $bIsBot;
286
  }
312
  * @param string $ip
313
  * @return bool
314
  */
315
+ public function isIp_ManageWP( $ip ) :bool {
316
  return $this->isIpInCollection( $ip, $this->getIpsForSlug( 'managewp' ) );
317
  }
318
 
319
+ /**
320
+ * @param string $ip
321
+ * @return bool
322
+ */
323
+ public function isIp_PayPal( $ip ) :bool {
324
+ return $this->isIpInCollection( $ip, $this->getIpsForSlug( 'paypal_ipn' ) );
325
+ }
326
+
327
  /**
328
  * @param string $ip
329
  * @param string $agent
330
  * @return bool
331
  */
332
+ public function isIp_Pingdom( $ip, $agent ) :bool {
333
  return ( stripos( $agent, 'pingdom.com' ) !== false )
334
  && $this->isIpInCollection( $ip, $this->getIpsForSlug( 'pingdom' ) );
335
  }
336
 
337
  /**
338
+ * @param string $ip
339
+ * @param string $agent
340
  * @return bool
341
  */
342
+ public function isIp_Stripe( $ip, $agent ) :bool {
343
+ return ( stripos( $agent, 'Stripe/' ) !== false )
344
+ && $this->isIpInCollection( $ip, $this->getIpsForSlug( 'stripe' ) );
345
  }
346
 
347
  /**
377
  }
378
 
379
  public function isIp_UptimeRobot( $ip, $agent ) :bool {
380
+ return ( empty( $agent ) || ( stripos( $agent, 'UptimeRobot' ) !== false ) )
381
  && $this->isIpInCollection( $ip, $this->getIpsForSlug( 'uptimerobot' ) );
382
  }
383
 
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Feedback.php RENAMED
@@ -2,7 +2,7 @@
2
 
3
  namespace ZxcvbnPhp;
4
 
5
- use ZxcvbnPhp\Matchers\Match;
6
 
7
  /**
8
  * Feedback - gives some user guidance based on the strength
@@ -13,8 +13,8 @@ use ZxcvbnPhp\Matchers\Match;
13
  class Feedback
14
  {
15
  /**
16
- * @param int $score
17
- * @param Match[] $sequence
18
  * @return array
19
  */
20
  public function getFeedback($score, array $sequence)
2
 
3
  namespace ZxcvbnPhp;
4
 
5
+ use ZxcvbnPhp\Matchers\BaseMatch;
6
 
7
  /**
8
  * Feedback - gives some user guidance based on the strength
13
  class Feedback
14
  {
15
  /**
16
+ * @param int $score
17
+ * @param BaseMatch[] $sequence
18
  * @return array
19
  */
20
  public function getFeedback($score, array $sequence)
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matcher.php RENAMED
@@ -2,27 +2,27 @@
2
 
3
  namespace ZxcvbnPhp;
4
 
5
- use ZxcvbnPhp\Matchers\Match;
6
 
7
  class Matcher
8
  {
9
  /**
10
  * Get matches for a password.
11
  *
12
- * @see zxcvbn/src/matching.coffee::omnimatch
13
- *
14
  * @param string $password Password string to match
15
  * @param array $userInputs Array of values related to the user (optional)
16
  * @code array('Alice Smith')
17
  * @endcode
18
  *
19
- * @return Match[] Array of Match objects.
 
 
20
  */
21
  public function getMatches($password, array $userInputs = [])
22
  {
23
  $matches = [];
24
  foreach ($this->getMatchers() as $matcher) {
25
- $matched = $matcher::match($password, $userInputs);
26
  if (is_array($matched) && !empty($matched)) {
27
  $matches = array_merge($matches, $matched);
28
  }
@@ -62,7 +62,7 @@ class Matcher
62
  return $result;
63
  }
64
 
65
- public static function compareMatches(Match $a, Match $b)
66
  {
67
  $beginDiff = $a->begin - $b->begin;
68
  if ($beginDiff) {
@@ -74,7 +74,7 @@ class Matcher
74
  /**
75
  * Load available Match objects to match against a password.
76
  *
77
- * @return array Array of classes implementing MatchInterface
78
  */
79
  protected function getMatchers()
80
  {
2
 
3
  namespace ZxcvbnPhp;
4
 
5
+ use ZxcvbnPhp\Matchers\BaseMatch;
6
 
7
  class Matcher
8
  {
9
  /**
10
  * Get matches for a password.
11
  *
 
 
12
  * @param string $password Password string to match
13
  * @param array $userInputs Array of values related to the user (optional)
14
  * @code array('Alice Smith')
15
  * @endcode
16
  *
17
+ * @return BaseMatch[] Array of Match objects.
18
+ *@see zxcvbn/src/matching.coffee::omnimatch
19
+ *
20
  */
21
  public function getMatches($password, array $userInputs = [])
22
  {
23
  $matches = [];
24
  foreach ($this->getMatchers() as $matcher) {
25
+ $matched = $matcher::doMatch($password, $userInputs);
26
  if (is_array($matched) && !empty($matched)) {
27
  $matches = array_merge($matches, $matched);
28
  }
62
  return $result;
63
  }
64
 
65
+ public static function compareMatches(BaseMatch $a, BaseMatch $b)
66
  {
67
  $beginDiff = $a->begin - $b->begin;
68
  if ($beginDiff) {
74
  /**
75
  * Load available Match objects to match against a password.
76
  *
77
+ * @return BaseMatch[] of classes implementing MatchInterface
78
  */
79
  protected function getMatchers()
80
  {
src/lib/vendor/{mkopinsky/zxcvbn-php/src/Matchers/Match.php → fernleafsystems/zxcvbn-php/src/Matchers/BaseMatch.php} RENAMED
@@ -4,7 +4,7 @@ namespace ZxcvbnPhp\Matchers;
4
 
5
  use ZxcvbnPhp\Scorer;
6
 
7
- abstract class Match implements MatchInterface
8
  {
9
 
10
  /**
4
 
5
  use ZxcvbnPhp\Scorer;
6
 
7
+ abstract class BaseMatch implements MatchInterface
8
  {
9
 
10
  /**
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/Bruteforce.php RENAMED
@@ -10,7 +10,7 @@ use ZxcvbnPhp\Scorer;
10
  *
11
  * Intentionally not named with Match suffix to prevent autoloading from Matcher.
12
  */
13
- class Bruteforce extends Match
14
  {
15
 
16
  const BRUTEFORCE_CARDINALITY = 10;
@@ -22,7 +22,7 @@ class Bruteforce extends Match
22
  * @param array $userInputs
23
  * @return Bruteforce[]
24
  */
25
- public static function match($password, array $userInputs = [])
26
  {
27
  // Matches entire string.
28
  $match = new static($password, 0, mb_strlen($password) - 1, $password);
10
  *
11
  * Intentionally not named with Match suffix to prevent autoloading from Matcher.
12
  */
13
+ class Bruteforce extends BaseMatch
14
  {
15
 
16
  const BRUTEFORCE_CARDINALITY = 10;
22
  * @param array $userInputs
23
  * @return Bruteforce[]
24
  */
25
+ public static function doMatch($password, array $userInputs = [])
26
  {
27
  // Matches entire string.
28
  $match = new static($password, 0, mb_strlen($password) - 1, $password);
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/DateMatch.php RENAMED
@@ -4,7 +4,7 @@ namespace ZxcvbnPhp\Matchers;
4
 
5
  use ZxcvbnPhp\Matcher;
6
 
7
- class DateMatch extends Match
8
  {
9
  const NUM_YEARS = 119; // Years match against 1900 - 2019
10
  const NUM_MONTHS = 12;
@@ -73,7 +73,7 @@ class DateMatch extends Match
73
  * @param array $userInputs
74
  * @return DateMatch[]
75
  */
76
- public static function match($password, array $userInputs = [])
77
  {
78
  # a "date" is recognized as:
79
  # any 3-tuple that starts or ends with a 2- or 4-digit year,
4
 
5
  use ZxcvbnPhp\Matcher;
6
 
7
+ class DateMatch extends BaseMatch
8
  {
9
  const NUM_YEARS = 119; // Years match against 1900 - 2019
10
  const NUM_MONTHS = 12;
73
  * @param array $userInputs
74
  * @return DateMatch[]
75
  */
76
+ public static function doMatch($password, array $userInputs = [])
77
  {
78
  # a "date" is recognized as:
79
  # any 3-tuple that starts or ends with a 2- or 4-digit year,
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/DictionaryMatch.php RENAMED
@@ -4,7 +4,7 @@ namespace ZxcvbnPhp\Matchers;
4
 
5
  use ZxcvbnPhp\Matcher;
6
 
7
- class DictionaryMatch extends Match
8
  {
9
 
10
  public $pattern = 'dictionary';
@@ -40,7 +40,7 @@ class DictionaryMatch extends Match
40
  * @param array $rankedDictionaries
41
  * @return DictionaryMatch[]
42
  */
43
- public static function match($password, array $userInputs = [], $rankedDictionaries = [])
44
  {
45
  $matches = [];
46
  if ($rankedDictionaries) {
4
 
5
  use ZxcvbnPhp\Matcher;
6
 
7
+ class DictionaryMatch extends BaseMatch
8
  {
9
 
10
  public $pattern = 'dictionary';
40
  * @param array $rankedDictionaries
41
  * @return DictionaryMatch[]
42
  */
43
+ public static function doMatch($password, array $userInputs = [], $rankedDictionaries = [])
44
  {
45
  $matches = [];
46
  if ($rankedDictionaries) {
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/L33tMatch.php RENAMED
@@ -28,7 +28,7 @@ class L33tMatch extends DictionaryMatch
28
  * @param array $rankedDictionaries
29
  * @return L33tMatch[]
30
  */
31
- public static function match($password, array $userInputs = [], $rankedDictionaries = [])
32
  {
33
  // Translate l33t password and dictionary match the translated password.
34
  $maps = array_filter(static::getL33tSubstitutions(static::getL33tSubtable($password)));
@@ -45,7 +45,7 @@ class L33tMatch extends DictionaryMatch
45
  $translatedWord = static::translate($password, $map);
46
 
47
  /** @var L33tMatch[] $results */
48
- $results = parent::match($translatedWord, $userInputs, $rankedDictionaries);
49
  foreach ($results as $match) {
50
  $token = mb_substr($password, $match->begin, $match->end - $match->begin + 1);
51
 
28
  * @param array $rankedDictionaries
29
  * @return L33tMatch[]
30
  */
31
+ public static function doMatch($password, array $userInputs = [], $rankedDictionaries = [])
32
  {
33
  // Translate l33t password and dictionary match the translated password.
34
  $maps = array_filter(static::getL33tSubstitutions(static::getL33tSubtable($password)));
45
  $translatedWord = static::translate($password, $map);
46
 
47
  /** @var L33tMatch[] $results */
48
+ $results = parent::doMatch($translatedWord, $userInputs, $rankedDictionaries);
49
  foreach ($results as $match) {
50
  $token = mb_substr($password, $match->begin, $match->end - $match->begin + 1);
51
 
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/MatchInterface.php RENAMED
@@ -14,7 +14,7 @@ interface MatchInterface
14
  *
15
  * @return array Array of Match objects
16
  */
17
- public static function match($password, array $userInputs = []);
18
 
19
  /**
20
  * @return integer
14
  *
15
  * @return array Array of Match objects
16
  */
17
+ public static function doMatch($password, array $userInputs = []);
18
 
19
  /**
20
  * @return integer
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/RepeatMatch.php RENAMED
@@ -5,7 +5,7 @@ namespace ZxcvbnPhp\Matchers;
5
  use ZxcvbnPhp\Matcher;
6
  use ZxcvbnPhp\Scorer;
7
 
8
- class RepeatMatch extends Match
9
  {
10
  const GREEDY_MATCH = '/(.+)\1+/u';
11
  const LAZY_MATCH = '/(.+?)\1+/u';
@@ -13,7 +13,7 @@ class RepeatMatch extends Match
13
 
14
  public $pattern = 'repeat';
15
 
16
- /** @var Match[] An array of matches for the repeated section itself. */
17
  public $baseMatches = [];
18
 
19
  /** @var int The number of guesses required for the repeated section itself. */
@@ -32,7 +32,7 @@ class RepeatMatch extends Match
32
  * @param array $userInputs
33
  * @return RepeatMatch[]
34
  */
35
- public static function match($password, array $userInputs = [])
36
  {
37
  $matches = [];
38
  $lastIndex = 0;
5
  use ZxcvbnPhp\Matcher;
6
  use ZxcvbnPhp\Scorer;
7
 
8
+ class RepeatMatch extends BaseMatch
9
  {
10
  const GREEDY_MATCH = '/(.+)\1+/u';
11
  const LAZY_MATCH = '/(.+?)\1+/u';
13
 
14
  public $pattern = 'repeat';
15
 
16
+ /** @var BaseMatch[] An array of matches for the repeated section itself. */
17
  public $baseMatches = [];
18
 
19
  /** @var int The number of guesses required for the repeated section itself. */
32
  * @param array $userInputs
33
  * @return RepeatMatch[]
34
  */
35
+ public static function doMatch($password, array $userInputs = [])
36
  {
37
  $matches = [];
38
  $lastIndex = 0;
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/ReverseDictionaryMatch.php RENAMED
@@ -17,10 +17,10 @@ class ReverseDictionaryMatch extends DictionaryMatch
17
  * @param array $rankedDictionaries
18
  * @return ReverseDictionaryMatch[]
19
  */
20
- public static function match($password, array $userInputs = [], $rankedDictionaries = [])
21
  {
22
  /** @var ReverseDictionaryMatch[] $matches */
23
- $matches = parent::match(self::mbStrRev($password), $userInputs, $rankedDictionaries);
24
  foreach ($matches as $match) {
25
  $tempBegin = $match->begin;
26
 
17
  * @param array $rankedDictionaries
18
  * @return ReverseDictionaryMatch[]
19
  */
20
+ public static function doMatch($password, array $userInputs = [], $rankedDictionaries = [])
21
  {
22
  /** @var ReverseDictionaryMatch[] $matches */
23
+ $matches = parent::doMatch(self::mbStrRev($password), $userInputs, $rankedDictionaries);
24
  foreach ($matches as $match) {
25
  $tempBegin = $match->begin;
26
 
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/SequenceMatch.php RENAMED
@@ -2,7 +2,7 @@
2
 
3
  namespace ZxcvbnPhp\Matchers;
4
 
5
- class SequenceMatch extends Match
6
  {
7
  const MAX_DELTA = 5;
8
 
@@ -24,7 +24,7 @@ class SequenceMatch extends Match
24
  * @param array $userInputs
25
  * @return SequenceMatch[]
26
  */
27
- public static function match($password, array $userInputs = [])
28
  {
29
  $matches = [];
30
  $passwordLength = mb_strlen($password);
2
 
3
  namespace ZxcvbnPhp\Matchers;
4
 
5
+ class SequenceMatch extends BaseMatch
6
  {
7
  const MAX_DELTA = 5;
8
 
24
  * @param array $userInputs
25
  * @return SequenceMatch[]
26
  */
27
+ public static function doMatch($password, array $userInputs = [])
28
  {
29
  $matches = [];
30
  $passwordLength = mb_strlen($password);
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/SpatialMatch.php RENAMED
@@ -4,7 +4,7 @@ namespace ZxcvbnPhp\Matchers;
4
 
5
  use ZxcvbnPhp\Matcher;
6
 
7
- class SpatialMatch extends Match
8
  {
9
  const SHIFTED_CHARACTERS = '~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?';
10
 
@@ -36,7 +36,7 @@ class SpatialMatch extends Match
36
  * @param array $graphs
37
  * @return SpatialMatch[]
38
  */
39
- public static function match($password, array $userInputs = [], array $graphs = [])
40
  {
41
 
42
  $matches = [];
4
 
5
  use ZxcvbnPhp\Matcher;
6
 
7
+ class SpatialMatch extends BaseMatch
8
  {
9
  const SHIFTED_CHARACTERS = '~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?';
10
 
36
  * @param array $graphs
37
  * @return SpatialMatch[]
38
  */
39
+ public static function doMatch($password, array $userInputs = [], array $graphs = [])
40
  {
41
 
42
  $matches = [];
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/YearMatch.php RENAMED
@@ -4,7 +4,7 @@ namespace ZxcvbnPhp\Matchers;
4
 
5
  use ZxcvbnPhp\Matcher;
6
 
7
- class YearMatch extends Match
8
  {
9
 
10
  const NUM_YEARS = 119;
@@ -19,7 +19,7 @@ class YearMatch extends Match
19
  * @param array $userInputs
20
  * @return YearMatch[]
21
  */
22
- public static function match($password, array $userInputs = [])
23
  {
24
  $matches = [];
25
  $groups = static::findAll($password, "/(19\d\d|200\d|201\d)/u");
4
 
5
  use ZxcvbnPhp\Matcher;
6
 
7
+ class YearMatch extends BaseMatch
8
  {
9
 
10
  const NUM_YEARS = 119;
19
  * @param array $userInputs
20
  * @return YearMatch[]
21
  */
22
+ public static function doMatch($password, array $userInputs = [])
23
  {
24
  $matches = [];
25
  $groups = static::findAll($password, "/(19\d\d|200\d|201\d)/u");
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/adjacency_graphs.json RENAMED
File without changes
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Matchers/frequency_lists.json RENAMED
File without changes
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Scorer.php RENAMED
@@ -3,7 +3,7 @@
3
  namespace ZxcvbnPhp;
4
 
5
  use ZxcvbnPhp\Matchers\Bruteforce;
6
- use ZxcvbnPhp\Matchers\Match;
7
 
8
  /**
9
  * scorer - takes a list of potential matches, ranks and evaluates them,
@@ -53,9 +53,9 @@ class Scorer
53
  * sequences before length-3. assuming at minimum D guesses per pattern type,
54
  * D^(l-1) approximates Sum(D^i for i in [1..l-1]
55
  *
56
- * @param string $password
57
- * @param Match[] $matches
58
- * @param bool $excludeAdditive
59
  * @return array Returns an array with these keys: [password, guesses, guesses_log10, sequence]
60
  */
61
  public function getMostGuessableMatchSequence($password, $matches, $excludeAdditive = false)
@@ -75,8 +75,8 @@ class Scorer
75
  // small detail: for deterministic output, sort each sublist by i.
76
  foreach ($matchesByEndIndex as &$matches) {
77
  usort($matches, function ($a, $b) {
78
- /** @var $a Match */
79
- /** @var $b Match */
80
  return $a->begin - $b->begin;
81
  });
82
  }
@@ -97,7 +97,7 @@ class Scorer
97
  ];
98
 
99
  for ($k = 0; $k < $length; $k++) {
100
- /** @var Match $match */
101
  foreach ($matchesByEndIndex[$k] as $match) {
102
  if ($match->begin > 0) {
103
  foreach ($this->optimal['m'][$match->begin - 1] as $l => $null) {
@@ -132,8 +132,8 @@ class Scorer
132
  /**
133
  * helper: considers whether a length-l sequence ending at match m is better (fewer guesses)
134
  * than previously encountered sequences, updating state if so.
135
- * @param Match $match
136
- * @param int $length
137
  */
138
  protected function update($match, $length)
139
  {
@@ -224,7 +224,7 @@ class Scorer
224
  /**
225
  * helper: step backwards through optimal.m starting at the end, constructing the final optimal match sequence.
226
  * @param int $n
227
- * @return Match[] array
228
  */
229
  protected function unwind($n)
230
  {
3
  namespace ZxcvbnPhp;
4
 
5
  use ZxcvbnPhp\Matchers\Bruteforce;
6
+ use ZxcvbnPhp\Matchers\BaseMatch;
7
 
8
  /**
9
  * scorer - takes a list of potential matches, ranks and evaluates them,
53
  * sequences before length-3. assuming at minimum D guesses per pattern type,
54
  * D^(l-1) approximates Sum(D^i for i in [1..l-1]
55
  *
56
+ * @param string $password
57
+ * @param BaseMatch[] $matches
58
+ * @param bool $excludeAdditive
59
  * @return array Returns an array with these keys: [password, guesses, guesses_log10, sequence]
60
  */
61
  public function getMostGuessableMatchSequence($password, $matches, $excludeAdditive = false)
75
  // small detail: for deterministic output, sort each sublist by i.
76
  foreach ($matchesByEndIndex as &$matches) {
77
  usort($matches, function ($a, $b) {
78
+ /** @var $a BaseMatch */
79
+ /** @var $b BaseMatch */
80
  return $a->begin - $b->begin;
81
  });
82
  }
97
  ];
98
 
99
  for ($k = 0; $k < $length; $k++) {
100
+ /** @var BaseMatch $match */
101
  foreach ($matchesByEndIndex[$k] as $match) {
102
  if ($match->begin > 0) {
103
  foreach ($this->optimal['m'][$match->begin - 1] as $l => $null) {
132
  /**
133
  * helper: considers whether a length-l sequence ending at match m is better (fewer guesses)
134
  * than previously encountered sequences, updating state if so.
135
+ * @param BaseMatch $match
136
+ * @param int $length
137
  */
138
  protected function update($match, $length)
139
  {
224
  /**
225
  * helper: step backwards through optimal.m starting at the end, constructing the final optimal match sequence.
226
  * @param int $n
227
+ * @return BaseMatch[] array
228
  */
229
  protected function unwind($n)
230
  {
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/TimeEstimator.php RENAMED
File without changes
src/lib/vendor/{mkopinsky → fernleafsystems}/zxcvbn-php/src/Zxcvbn.php RENAMED
File without changes
src/lib/vendor/twig/twig/src/Node/IncludeNode.php CHANGED
@@ -22,7 +22,7 @@ use Twig\Node\Expression\AbstractExpression;
22
  */
23
  class IncludeNode extends Node implements NodeOutputInterface
24
  {
25
- public function __construct(AbstractExpression $expr, AbstractExpression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
26
  {
27
  $nodes = ['expr' => $expr];
28
  if (null !== $variables) {
22
  */
23
  class IncludeNode extends Node implements NodeOutputInterface
24
  {
25
+ public function __construct(AbstractExpression $expr, AbstractExpression $variables = null, $only = false, $ignoreMissing = false, $lineno = 0, $tag = null)
26
  {
27
  $nodes = ['expr' => $expr];
28
  if (null !== $variables) {
src/processors/usermanagement_suspend.php DELETED
@@ -1,198 +0,0 @@
1
- <?php
2
-
3
- use FernleafSystems\Wordpress\Plugin\Shield\Modules;
4
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions;
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Suspend;
7
- use FernleafSystems\Wordpress\Services\Services;
8
-
9
- /**
10
- * Class ICWP_WPSF_Processor_UserManagement_Suspend
11
- * @deprecated 10.0
12
- */
13
- class ICWP_WPSF_Processor_UserManagement_Suspend extends Modules\BaseShield\ShieldProcessor {
14
-
15
- public function run() {
16
- /** @var UserManagement\Options $opts */
17
- $opts = $this->getOptions();
18
-
19
- if ( $opts->isSuspendManualEnabled() ) {
20
- $this->setupUserFilters();
21
- ( new Suspend\Suspended() )
22
- ->setMod( $this->getMod() )
23
- ->run();
24
- }
25
-
26
- if ( $opts->isSuspendAutoIdleEnabled() ) {
27
- ( new Suspend\Idle() )
28
- ->setMod( $this->getMod() )
29
- ->run();
30
- }
31
-
32
- if ( $opts->isSuspendAutoPasswordEnabled() ) {
33
- ( new Suspend\PasswordExpiry() )
34
- ->setMaxPasswordAge( $opts->getPassExpireTimeout() )
35
- ->setMod( $this->getMod() )
36
- ->run();
37
- }
38
- }
39
-
40
- public function runHourlyCron() {
41
- $this->updateUserMetaVersion();
42
- }
43
-
44
- /**
45
- * Run from CRON
46
- * Updates all user meta versions. Limits to 25 users at a time via the cron
47
- */
48
- private function updateUserMetaVersion() {
49
- $oCon = $this->getCon();
50
- $nVersion = $oCon->getVersionNumeric();
51
- $sMetaKey = $oCon->prefix( 'meta-version' );
52
-
53
- $nCount = 0;
54
-
55
- $oUserIt = new \FernleafSystems\Wordpress\Services\Utilities\Iterators\WpUserIterator();
56
- $oUserIt->filterByMeta( $sMetaKey, $nVersion, 'NOT EXISTS' );
57
- foreach ( $oUserIt as $oUser ) {
58
- $oCon->getUserMeta( $oUser );
59
- if ( $nCount++ > 25 ) {
60
- break;
61
- }
62
- }
63
-
64
- $oUserIt = new \FernleafSystems\Wordpress\Services\Utilities\Iterators\WpUserIterator();
65
- $oUserIt->filterByMeta( $sMetaKey, $nVersion, '<' );
66
- foreach ( $oUserIt as $oUser ) {
67
- $oCon->getUserMeta( $oUser );
68
- if ( $nCount++ > 25 ) {
69
- break;
70
- }
71
- }
72
- }
73
-
74
- /**
75
- * Sets-up all the UI filters necessary to provide manual user suspension and filter the User Tables
76
- */
77
- private function setupUserFilters() {
78
- /** @var UserManagement\Options $oOpts */
79
- $oOpts = $this->getOptions();
80
-
81
- // User profile UI
82
- add_filter( 'edit_user_profile', [ $this, 'addUserBlockOption' ], 1, 1 );
83
- add_action( 'edit_user_profile_update', [ $this, 'handleUserSuspendOptionSubmit' ] );
84
-
85
- // Display suspended on the user list table
86
- add_filter( 'manage_users_columns', [ $this, 'addUserListSuspendedFlag' ] );
87
-
88
- // Provide Suspended user filter above table
89
- $aUserIds = array_keys( $oOpts->getSuspendHardUserIds() );
90
- if ( !empty( $aUserIds ) ) {
91
- // Provide the link above the table.
92
- add_filter( 'views_users', function ( $aViews ) use ( $aUserIds ) {
93
- $aViews[ 'shield_suspended_users' ] = sprintf( '<a href="%s">%s</a>',
94
- add_query_arg( [ 'suspended' => 1 ], Services::WpGeneral()->getUrl_CurrentAdminPage() ),
95
- sprintf( '%s (%s)', __( 'Suspended', 'wp-simple-firewall' ), count( $aUserIds ) ) );
96
- return $aViews;
97
- } );
98
-
99
- // Filter the database query
100
- add_filter( 'users_list_table_query_args', function ( $aQueryArgs ) use ( $aUserIds ) {
101
- if ( is_array( $aQueryArgs ) && Services::Request()->query( 'suspended' ) ) {
102
- $aQueryArgs[ 'include' ] = $aUserIds;
103
- }
104
- return $aQueryArgs;
105
- } );
106
- }
107
- }
108
-
109
- /**
110
- * @param array $aColumns
111
- * @return array
112
- */
113
- public function addUserListSuspendedFlag( $aColumns ) {
114
-
115
- $sCustomColumnName = $this->getCon()->prefix( 'col_user_status' );
116
- if ( !isset( $aColumns[ $sCustomColumnName ] ) ) {
117
- $aColumns[ $sCustomColumnName ] = __( 'User Status', 'wp-simple-firewall' );
118
- }
119
-
120
- add_filter( 'manage_users_custom_column',
121
- function ( $sContent, $sColumnName, $nUserId ) use ( $sCustomColumnName ) {
122
-
123
- if ( $sColumnName == $sCustomColumnName ) {
124
- $oUser = Services::WpUsers()->getUserById( $nUserId );
125
- if ( $oUser instanceof \WP_User ) {
126
- $oMeta = $this->getCon()->getUserMeta( $oUser );
127
- if ( $oMeta->hard_suspended_at > 0 ) {
128
- $sNewContent = sprintf( '%s: %s',
129
- __( 'Suspended', 'wp-simple-firewall' ),
130
- Services::Request()
131
- ->carbon( true )
132
- ->setTimestamp( $oMeta->hard_suspended_at )
133
- ->diffForHumans()
134
- );
135
- $sContent = empty( $sContent ) ? $sNewContent : $sContent.'<br/>'.$sNewContent;
136
- }
137
- }
138
- }
139
-
140
- return $sContent;
141
- },
142
- 10, 3
143
- );
144
-
145
- return $aColumns;
146
- }
147
-
148
- /**
149
- * @param \WP_User $oUser
150
- */
151
- public function addUserBlockOption( $oUser ) {
152
- $oCon = $this->getCon();
153
- $oMeta = $oCon->getUserMeta( $oUser );
154
- $oWpUsers = Services::WpUsers();
155
-
156
- $aData = [
157
- 'strings' => [
158
- 'title' => __( 'Suspend Account', 'wp-simple-firewall' ),
159
- 'label' => __( 'Check to un/suspend user account', 'wp-simple-firewall' ),
160
- 'description' => __( 'The user can never login while their account is suspended.', 'wp-simple-firewall' ),
161
- 'cant_manage' => __( 'Sorry, suspension for this account may only be managed by a security administrator.', 'wp-simple-firewall' ),
162
- 'since' => sprintf( '%s: %s', __( 'Suspended', 'wp-simple-firewall' ),
163
- Services::WpGeneral()->getTimeStringForDisplay( $oMeta->hard_suspended_at ) ),
164
- ],
165
- 'flags' => [
166
- 'can_manage_suspension' => !$oWpUsers->isUserAdmin( $oUser ) || $oCon->isPluginAdmin(),
167
- 'is_suspended' => $oMeta->hard_suspended_at > 0
168
- ],
169
- 'vars' => [
170
- 'form_field' => 'shield_suspend_user',
171
- ]
172
- ];
173
- echo $this->getMod()->renderTemplate( '/snippets/user/profile/suspend.twig', $aData, true );
174
- }
175
-
176
- /**
177
- * @param int $nUserId
178
- */
179
- public function handleUserSuspendOptionSubmit( $nUserId ) {
180
- $oCon = $this->getCon();
181
- $oWpUsers = Services::WpUsers();
182
-
183
- $oEditedUser = $oWpUsers->getUserById( $nUserId );
184
-
185
- if ( !$oWpUsers->isUserAdmin( $oEditedUser ) || $oCon->isPluginAdmin() ) {
186
- $bIsSuspend = Services::Request()->post( 'shield_suspend_user' ) === 'Y';
187
- /** @var \ICWP_WPSF_FeatureHandler_UserManagement $mod */
188
- $mod = $this->getMod();
189
- $mod->addRemoveHardSuspendUserId( $nUserId, $bIsSuspend );
190
-
191
- if ( $bIsSuspend ) { // Delete any existing user sessions
192
- ( new Sessions\Lib\Ops\Terminate() )
193
- ->setMod( $oCon->getModule_Sessions() )
194
- ->byUsername( $oEditedUser->user_login );
195
- }
196
- }
197
- }
198
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/twig/notices/plugin-too-old.twig ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ {% extends "/notices/base-error.twig" %}
2
+
3
+ {% block notice_body %}
4
+ {% for line in strings.lines %}
5
+ <p>{{ line }}</p>
6
+ {% endfor %}
7
+ <p><a href="{{ hrefs.click_update }}">{{ strings.click_update }}</a></p>
8
+ {% endblock %}