Shield Security for WordPress - Version 13.0.6

Version Description

Download this release

Release Info

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

Code changes from version 13.0.5 to 13.0.6

Files changed (38) hide show
  1. cl.json +27 -0
  2. config/lockdown.json +5 -9
  3. icwp-wpsf.php +1 -1
  4. plugin-spec.php +3 -3
  5. plugin.json +3 -3
  6. readme.txt +1 -1
  7. src/lib/src/Databases/IPs/Handler.php +4 -0
  8. src/lib/src/Databases/IPs/Insert.php +4 -0
  9. src/lib/src/Databases/IPs/Update.php +13 -0
  10. src/lib/src/Modules/Base/ModCon.php +18 -17
  11. src/lib/src/Modules/Base/Options.php +33 -78
  12. src/lib/src/Modules/Base/Options/BuildForDisplay.php +256 -0
  13. src/lib/src/Modules/Base/UI.php +8 -144
  14. src/lib/src/Modules/BaseShield/ModCon.php +7 -15
  15. src/lib/src/Modules/BaseShield/UI.php +2 -1
  16. src/lib/src/Modules/HackGuard/Render/ScanResults/SectionThemes.php +28 -0
  17. src/lib/src/Modules/HackGuard/UI.php +1 -13
  18. src/lib/src/Modules/IPs/AjaxHandler.php +3 -3
  19. src/lib/src/Modules/IPs/Lib/Ops/AddIp.php +6 -14
  20. src/lib/src/Modules/IPs/UI.php +1 -1
  21. src/lib/src/Modules/IPs/WpCli/Add.php +2 -4
  22. src/lib/src/Modules/Integrations/UI.php +2 -2
  23. src/lib/src/Modules/Lockdown/ModCon.php +3 -0
  24. src/lib/src/Modules/Lockdown/Options.php +7 -16
  25. src/lib/src/Modules/Lockdown/Strings.php +33 -11
  26. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php +1 -0
  27. src/lib/src/Modules/LoginGuard/UI.php +2 -2
  28. src/lib/src/Modules/Plugin/Lib/Debug/Collate.php +16 -12
  29. src/lib/src/Modules/Plugin/UI.php +1 -15
  30. src/lib/src/Modules/SecurityAdmin/UI.php +1 -1
  31. src/lib/src/Modules/Traffic/UI.php +1 -1
  32. src/lib/src/Tables/Render/WpListTable/AdminNotes.php +2 -6
  33. src/lib/src/Tables/Render/WpListTable/IpBase.php +5 -1
  34. src/lib/src/Tables/Render/WpListTable/IpBlack.php +8 -8
  35. src/lib/vendor/fernleafsystems/wordpress-services/src/Core/General.php +13 -1
  36. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Hashes/ClassicPress.php +0 -4
  37. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/WpOrg/Cp/Download.php +2 -3
  38. templates/twig/components/options_form/option.twig +12 -17
cl.json CHANGED
@@ -165,6 +165,33 @@
165
  "title": "Prevent some fatal errors when integrating with 3rd parties and their data isn't as expected.",
166
  "description": [],
167
  "patch": "13.0.5"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  }
169
  ]
170
  },
165
  "title": "Prevent some fatal errors when integrating with 3rd parties and their data isn't as expected.",
166
  "description": [],
167
  "patch": "13.0.5"
168
+ },
169
+ {
170
+ "type": "improved",
171
+ "title": "Improved handling of ClassicPress versions and file scanning for migrated WP sites.",
172
+ "description": [],
173
+ "patch": "13.0.6"
174
+ },
175
+ {
176
+ "type": "changed",
177
+ "title": "Official WP.org themes that are inactive no longer display a warning in results tables.",
178
+ "description": [],
179
+ "patch": "13.0.6"
180
+ },
181
+ {
182
+ "type": "fixed",
183
+ "title": "[Minor Security Vulnerability] An authenticated (administrator+) Persistent XSS.",
184
+ "description": [
185
+ "Privately disclosed to us by Yoru Oni - thank you."
186
+ ],
187
+ "href": "https://shsec.io/kh",
188
+ "patch": "13.0.6"
189
+ },
190
+ {
191
+ "type": "changed",
192
+ "title": "It's now possible to add custom exclusions to the anonymous REST API block.",
193
+ "description": [],
194
+ "patch": "13.0.6"
195
  }
196
  ]
197
  },
config/lockdown.json CHANGED
@@ -103,11 +103,14 @@
103
  },
104
  {
105
  "key": "api_namespace_exclusions",
106
- "section": "section_non_ui",
107
  "default": [
108
  "contact-form-7",
109
  "jetpack",
110
- "woocommerce"
 
 
 
111
  ],
112
  "type": "array",
113
  "link_info": "",
@@ -175,13 +178,6 @@
175
  }
176
  ],
177
  "definitions": {
178
- "default_restapi_exclusions": [
179
- "contact-form-7",
180
- "jetpack",
181
- "tho",
182
- "wpstatistics",
183
- "woocommerce"
184
- ],
185
  "events": {
186
  "block_anonymous_restapi": {
187
  "audit_params": [
103
  },
104
  {
105
  "key": "api_namespace_exclusions",
106
+ "section": "section_apixml",
107
  "default": [
108
  "contact-form-7",
109
  "jetpack",
110
+ "tho",
111
+ "woocommerce",
112
+ "tribe",
113
+ "wpstatistics"
114
  ],
115
  "type": "array",
116
  "link_info": "",
178
  }
179
  ],
180
  "definitions": {
 
 
 
 
 
 
 
181
  "events": {
182
  "block_anonymous_restapi": {
183
  "audit_params": [
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: 13.0.5
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: 13.0.6
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
plugin-spec.php CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "13.0.5",
4
- "release_timestamp": 1641981192,
5
- "build": "202201.1201",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
1
  {
2
  "properties": {
3
+ "version": "13.0.6",
4
+ "release_timestamp": 1642088418,
5
+ "build": "202201.1301",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
plugin.json CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "13.0.5",
4
- "release_timestamp": 1641981192,
5
- "build": "202201.1201",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
1
  {
2
  "properties": {
3
+ "version": "13.0.6",
4
+ "release_timestamp": 1642088418,
5
+ "build": "202201.1301",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
readme.txt CHANGED
@@ -8,7 +8,7 @@ Requires at least: 3.7
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 5.9
11
- Stable tag: 13.0.4
12
 
13
  No-Nonsense Security Hardening that protects WordPress against hackers, malicious bots, and spammers (no captchas!). Now with exclusive ShieldNET Technology.
14
 
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 5.9
11
+ Stable tag: 13.0.6
12
 
13
  No-Nonsense Security Hardening that protects WordPress against hackers, malicious bots, and spammers (no captchas!). Now with exclusive ShieldNET Technology.
14
 
src/lib/src/Databases/IPs/Handler.php CHANGED
@@ -19,6 +19,10 @@ class Handler extends Base\Handler {
19
  ->query();
20
  }
21
 
 
 
 
 
22
  /**
23
  * @param int $timestamp
24
  * @return bool
19
  ->query();
20
  }
21
 
22
+ public function cleanLabel( string $label ) :string {
23
+ return trim( empty( $label ) ? '' : preg_replace( '#[^\sa-z0-9_-]#i', '', $label ) );
24
+ }
25
+
26
  /**
27
  * @param int $timestamp
28
  * @return bool
src/lib/src/Databases/IPs/Insert.php CHANGED
@@ -26,6 +26,10 @@ class Insert extends Base\Insert {
26
  $data[ 'is_range' ] = true;
27
  }
28
 
 
 
 
 
29
  return $this->setInsertData( $data );
30
  }
31
  }
26
  $data[ 'is_range' ] = true;
27
  }
28
 
29
+ /** @var Handler $dbh */
30
+ $dbh = $this->getDbH();
31
+ $data[ 'label' ] = $dbh->cleanLabel( $data[ 'label' ] ?? '' );
32
+
33
  return $this->setInsertData( $data );
34
  }
35
  }
src/lib/src/Databases/IPs/Update.php CHANGED
@@ -7,6 +7,19 @@ use FernleafSystems\Wordpress\Services\Services;
7
 
8
  class Update extends Base\Update {
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  /**
11
  * Also updates last access at
12
  * @param int $nIncrement
7
 
8
  class Update extends Base\Update {
9
 
10
+ /**
11
+ * @return array
12
+ */
13
+ public function getUpdateData() {
14
+ $data = parent::getUpdateData();
15
+ if ( !empty( $data[ 'label' ] ) ) {
16
+ /** @var Handler $dbh */
17
+ $dbh = $this->getDbH();
18
+ $data[ 'label' ] = $dbh->cleanLabel( $data[ 'label' ] );
19
+ }
20
+ return $data;
21
+ }
22
+
23
  /**
24
  * Also updates last access at
25
  * @param int $nIncrement
src/lib/src/Modules/Base/ModCon.php CHANGED
@@ -809,20 +809,15 @@ abstract class ModCon {
809
  }
810
 
811
  /**
812
- * @return array - map of each option to its option type
813
  */
814
- protected function getAllFormOptionsAndTypes() {
815
- $opts = [];
816
-
817
- foreach ( $this->getUIHandler()->buildOptions() as $aOptionsSection ) {
818
- if ( !empty( $aOptionsSection ) ) {
819
- foreach ( $aOptionsSection[ 'options' ] as $aOption ) {
820
- $opts[ $aOption[ 'key' ] ] = $aOption[ 'type' ];
821
- }
822
- }
823
- }
824
-
825
- return $opts;
826
  }
827
 
828
  protected function handleModAction( string $action ) {
@@ -898,9 +893,15 @@ abstract class ModCon {
898
  // standard options use b64 and fail-over to lz-string
899
  $form = FormParams::Retrieve( FormParams::ENC_BASE64 );
900
 
901
- foreach ( $this->getAllFormOptionsAndTypes() as $key => $optType ) {
 
 
 
 
 
 
902
 
903
- $optValue = $form[ $key ] ?? null;
904
  if ( is_null( $optValue ) ) {
905
 
906
  if ( in_array( $optType, [ 'text', 'email' ] ) ) { //text box, and it's null, don't update
@@ -930,7 +931,7 @@ abstract class ModCon {
930
  continue;
931
  }
932
 
933
- $confirm = $form[ $key.'_confirm' ] ?? null;
934
  if ( $sTempValue !== $confirm ) {
935
  throw new \Exception( __( 'Password values do not match.', 'wp-simple-firewall' ) );
936
  }
@@ -948,7 +949,7 @@ abstract class ModCon {
948
 
949
  // Prevent overwriting of non-editable fields
950
  if ( !in_array( $optType, [ 'noneditable_text' ] ) ) {
951
- $this->getOptions()->setOpt( $key, $optValue );
952
  }
953
  }
954
 
809
  }
810
 
811
  /**
812
+ * @deprecated 13.0.6
813
  */
814
+ protected function getAllFormOptionsAndTypes() :array {
815
+ return array_map(
816
+ function ( $optDef ) {
817
+ return $optDef[ 'type' ];
818
+ },
819
+ $this->getOptions()->getVisibleOptions()
820
+ );
 
 
 
 
 
821
  }
822
 
823
  protected function handleModAction( string $action ) {
893
  // standard options use b64 and fail-over to lz-string
894
  $form = FormParams::Retrieve( FormParams::ENC_BASE64 );
895
 
896
+ $optsAndTypes = array_map(
897
+ function ( $optDef ) {
898
+ return $optDef[ 'type' ];
899
+ },
900
+ $this->getOptions()->getVisibleOptions()
901
+ );
902
+ foreach ( $optsAndTypes as $optKey => $optType ) {
903
 
904
+ $optValue = $form[ $optKey ] ?? null;
905
  if ( is_null( $optValue ) ) {
906
 
907
  if ( in_array( $optType, [ 'text', 'email' ] ) ) { //text box, and it's null, don't update
931
  continue;
932
  }
933
 
934
+ $confirm = $form[ $optKey.'_confirm' ] ?? null;
935
  if ( $sTempValue !== $confirm ) {
936
  throw new \Exception( __( 'Password values do not match.', 'wp-simple-firewall' ) );
937
  }
949
 
950
  // Prevent overwriting of non-editable fields
951
  if ( !in_array( $optType, [ 'noneditable_text' ] ) ) {
952
+ $this->getOptions()->setOpt( $optKey, $optValue );
953
  }
954
  }
955
 
src/lib/src/Modules/Base/Options.php CHANGED
@@ -296,90 +296,45 @@ class Options {
296
  }
297
 
298
  /**
299
- * @return string[]
300
  */
301
- public function getVisibleOptionsKeys() :array {
302
- $keys = [];
303
-
304
- foreach ( $this->getRawData_AllOptions() as $optDef ) {
305
- if ( $optDef[ 'hidden' ] ?? false ) {
306
- continue;
307
- }
308
- $section = $this->getSection( $optDef[ 'section' ] );
309
- if ( empty( $section ) || ( $section[ 'hidden' ] ?? false ) ) {
310
- continue;
 
 
311
  }
 
 
312
 
313
- $keys[] = $optDef[ 'key' ];
314
- }
315
-
316
- return $keys;
 
 
 
317
  }
318
 
 
 
 
319
  public function getOptionsForPluginUse() :array {
320
-
321
- $optionsData = [];
322
-
323
- foreach ( $this->getRawData_OptionsSections() as $section ) {
324
-
325
- if ( isset( $section[ 'hidden' ] ) && $section[ 'hidden' ] ) {
326
- continue;
327
- }
328
-
329
- $section = array_merge(
330
- [
331
- 'primary' => false,
332
- 'options' => $this->getOptionsForSection( $section[ 'slug' ] ),
333
- 'help_video_id' => ''
334
- ],
335
- $section
336
- );
337
-
338
- if ( !empty( $section[ 'options' ] ) ) {
339
- $optionsData[] = $section;
340
- }
341
- }
342
-
343
- return $optionsData;
344
  }
345
 
 
 
 
346
  protected function getOptionsForSection( string $slug ) :array {
347
-
348
- $allOptions = [];
349
- foreach ( $this->getRawData_AllOptions() as $optDef ) {
350
-
351
- if ( ( $optDef[ 'section' ] != $slug ) || ( isset( $optDef[ 'hidden' ] ) && $optDef[ 'hidden' ] ) ) {
352
- continue;
353
- }
354
-
355
- if ( isset( $optDef[ 'hidden' ] ) && $optDef[ 'hidden' ] ) {
356
- continue;
357
- }
358
-
359
- $optDef = array_merge(
360
- [
361
- 'link_info' => '',
362
- 'link_blog' => '',
363
- 'help_video_id' => '',
364
- 'value_options' => [],
365
- 'premium' => false,
366
- 'advanced' => false
367
- ],
368
- $optDef
369
- );
370
- $optDef[ 'value' ] = $this->getOpt( $optDef[ 'key' ] );
371
-
372
- if ( in_array( $optDef[ 'type' ], [ 'select', 'multiple_select' ] ) ) {
373
- $convertedOptions = [];
374
- foreach ( $optDef[ 'value_options' ] as $selectValues ) {
375
- $convertedOptions[ $selectValues[ 'value_key' ] ] = __( $selectValues[ 'text' ], 'wp-simple-firewall' );
376
- }
377
- $optDef[ 'value_options' ] = $convertedOptions;
378
- }
379
-
380
- $allOptions[] = $optDef;
381
- }
382
- return $allOptions;
383
  }
384
 
385
  public function getAdditionalMenuItems() :array {
@@ -413,7 +368,7 @@ class Options {
413
  }
414
 
415
  /**
416
- * @param mixed $mDefault
417
  * @return mixed|null
418
  */
419
  public function getOptDefault( string $key, $mDefault = null ) {
@@ -426,8 +381,8 @@ class Options {
426
  }
427
 
428
  /**
429
- * @param mixed $mValueToTest
430
- * @param bool $strict
431
  */
432
  public function isOpt( string $key, $mValueToTest, $strict = false ) :bool {
433
  return $strict ? $this->getOpt( $key ) === $mValueToTest : $this->getOpt( $key ) == $mValueToTest;
296
  }
297
 
298
  /**
299
+ * @return array[]
300
  */
301
+ public function getVisibleOptions() :array {
302
+ return array_filter(
303
+ $this->getRawData_AllOptions(),
304
+ function ( $optDef ) {
305
+ if ( $optDef[ 'hidden' ] ?? false ) {
306
+ return null;
307
+ }
308
+ $section = $this->getSection( $optDef[ 'section' ] );
309
+ if ( empty( $section ) || ( $section[ 'hidden' ] ?? false ) ) {
310
+ return null;
311
+ }
312
+ return $optDef;
313
  }
314
+ );
315
+ }
316
 
317
+ /**
318
+ * @return string[]
319
+ */
320
+ public function getVisibleOptionsKeys() :array {
321
+ return array_map( function ( $optDef ) {
322
+ return $optDef[ 'key' ];
323
+ }, $this->getVisibleOptions() );
324
  }
325
 
326
+ /**
327
+ * @deprecated 13.0.6
328
+ */
329
  public function getOptionsForPluginUse() :array {
330
+ return [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  }
332
 
333
+ /**
334
+ * @deprecated 13.0.6
335
+ */
336
  protected function getOptionsForSection( string $slug ) :array {
337
+ return [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
338
  }
339
 
340
  public function getAdditionalMenuItems() :array {
368
  }
369
 
370
  /**
371
+ * @param mixed $mDefault
372
  * @return mixed|null
373
  */
374
  public function getOptDefault( string $key, $mDefault = null ) {
381
  }
382
 
383
  /**
384
+ * @param mixed $mValueToTest
385
+ * @param bool $strict
386
  */
387
  public function isOpt( string $key, $mValueToTest, $strict = false ) :bool {
388
  return $strict ? $this->getOpt( $key ) === $mValueToTest : $this->getOpt( $key ) == $mValueToTest;
src/lib/src/Modules/Base/Options/BuildForDisplay.php ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Options;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class BuildForDisplay {
9
+
10
+ use ModConsumer;
11
+
12
+ private $isWhitelabelled = false;
13
+
14
+ /**
15
+ * Will initiate the plugin options structure for use by the UI builder.
16
+ * It doesn't set any values, just populates the array created in buildOptions()
17
+ * with values stored.
18
+ * It has to handle the conversion of stored values to data to be displayed to the user.
19
+ */
20
+ public function standard() :array {
21
+ $con = $this->getCon();
22
+ $mod = $this->getMod();
23
+ $UI = $mod->getUIHandler();
24
+
25
+ $isPremium = $con->isPremiumExtensionsEnabled();
26
+ $showAdvanced = $con->getModule_Plugin()->isShowAdvanced();
27
+
28
+ $opts = $this->getOptions();
29
+ $sections = $this->buildAvailableSections();
30
+
31
+ foreach ( $sections as $sectionKey => $sect ) {
32
+
33
+ if ( !empty( $sect[ 'options' ] ) ) {
34
+
35
+ foreach ( $sect[ 'options' ] as $optKey => $option ) {
36
+ $option[ 'is_value_default' ] = ( $option[ 'value' ] === $option[ 'default' ] );
37
+ $isOptPremium = $option[ 'premium' ] ?? false;
38
+ $bIsAdv = $option[ 'advanced' ] ?? false;
39
+ if ( ( !$isOptPremium || $isPremium ) && ( !$bIsAdv || $showAdvanced ) ) {
40
+ $sect[ 'options' ][ $optKey ] = $this->buildOptionForUi( $option );
41
+ }
42
+ else {
43
+ unset( $sect[ 'options' ][ $optKey ] );
44
+ }
45
+ }
46
+
47
+ if ( empty( $sect[ 'options' ] ) ) {
48
+ unset( $sections[ $sectionKey ] );
49
+ }
50
+ else {
51
+ try {
52
+ $sect = array_merge(
53
+ $sect,
54
+ $this->getMod()
55
+ ->getStrings()
56
+ ->getSectionStrings( $sect[ 'slug' ] )
57
+ );
58
+ }
59
+ catch ( \Exception $e ) {
60
+ }
61
+ $sections[ $sectionKey ] = $sect;
62
+ }
63
+
64
+ if ( isset( $sections[ $sectionKey ] ) ) {
65
+ $warning = [];
66
+ if ( !$opts->isSectionReqsMet( $sect[ 'slug' ] ) ) {
67
+ $warning[] = __( 'Unfortunately your WordPress and/or PHP versions are too old to support this feature.', 'wp-simple-firewall' );
68
+ }
69
+ $sections[ $sectionKey ][ 'warnings' ] = array_merge(
70
+ $warning,
71
+ $UI->getSectionWarnings( $sect[ 'slug' ] )
72
+ );
73
+ $sections[ $sectionKey ][ 'notices' ] = $UI->getSectionNotices( $sect[ 'slug' ] );
74
+ }
75
+ }
76
+ }
77
+
78
+ return $sections;
79
+ }
80
+
81
+ protected function buildAvailableSections() :array {
82
+ $opts = $this->getOptions();
83
+
84
+ $optionsData = [];
85
+
86
+ foreach ( $opts->getSections() as $section ) {
87
+
88
+ $section = array_merge(
89
+ [
90
+ 'primary' => false,
91
+ 'options' => $this->buildOptionsForSection( $section[ 'slug' ] ),
92
+ 'beacon_id' => false,
93
+ ],
94
+ $section
95
+ );
96
+
97
+ if ( !empty( $section[ 'options' ] ) ) {
98
+
99
+ if ( $this->isWhitelabelled ) {
100
+ $section[ 'beacon_id' ] = false;
101
+ }
102
+
103
+ $optionsData[] = $section;
104
+ }
105
+ }
106
+
107
+ return $optionsData;
108
+ }
109
+
110
+ protected function buildOptionsForSection( string $section ) :array {
111
+ $opts = $this->getOptions();
112
+
113
+ $allOptions = [];
114
+ foreach ( $opts->getVisibleOptions() as $optDef ) {
115
+
116
+ if ( $optDef[ 'section' ] !== $section ) {
117
+ continue;
118
+ }
119
+
120
+ $optDef = array_merge(
121
+ [
122
+ 'link_info' => '',
123
+ 'link_blog' => '',
124
+ 'value_options' => [],
125
+ 'premium' => false,
126
+ 'advanced' => false,
127
+ 'beacon_id' => false
128
+ ],
129
+ $optDef
130
+ );
131
+ $optDef[ 'value' ] = $opts->getOpt( $optDef[ 'key' ] );
132
+
133
+ if ( in_array( $optDef[ 'type' ], [ 'select', 'multiple_select' ] ) ) {
134
+ $convertedOptions = [];
135
+ foreach ( $optDef[ 'value_options' ] as $selectValues ) {
136
+ $convertedOptions[ $selectValues[ 'value_key' ] ] = __( $selectValues[ 'text' ], 'wp-simple-firewall' );
137
+ }
138
+ $optDef[ 'value_options' ] = $convertedOptions;
139
+ }
140
+
141
+ if ( $this->isWhitelabelled ) {
142
+ $optDef[ 'beacon_id' ] = false;
143
+ }
144
+
145
+ $allOptions[] = $optDef;
146
+ }
147
+ return $allOptions;
148
+ }
149
+
150
+ protected function buildOptionForUi( array $option ) :array {
151
+
152
+ $value = $option[ 'value' ];
153
+
154
+ switch ( $option[ 'type' ] ) {
155
+
156
+ case 'password':
157
+ if ( !empty( $value ) ) {
158
+ $value = '';
159
+ }
160
+ break;
161
+
162
+ case 'array':
163
+ if ( empty( $value ) || !is_array( $value ) ) {
164
+ $value = [];
165
+ }
166
+
167
+ $option[ 'rows' ] = count( $value ) + 2;
168
+ $value = stripslashes( implode( "\n", $value ) );
169
+
170
+ break;
171
+
172
+ case 'comma_separated_lists':
173
+
174
+ $converted = [];
175
+ if ( !empty( $value ) && is_array( $value ) ) {
176
+ foreach ( $value as $page => $params ) {
177
+ $converted[] = $page.', '.implode( ", ", $params );
178
+ }
179
+ }
180
+ $option[ 'rows' ] = count( $converted ) + 1;
181
+ $value = implode( "\n", $converted );
182
+
183
+ break;
184
+
185
+ case 'multiple_select':
186
+ if ( !is_array( $value ) ) {
187
+ $value = [];
188
+ }
189
+ break;
190
+
191
+ case 'text':
192
+ $value = stripslashes( $this->getMod()->getTextOpt( $option[ 'key' ] ) );
193
+ break;
194
+ }
195
+
196
+ $params = [
197
+ 'value' => is_scalar( $value ) ? esc_attr( $value ) : $value,
198
+ 'disabled' => !$this->getCon()
199
+ ->isPremiumActive() && ( isset( $option[ 'premium' ] ) && $option[ 'premium' ] ),
200
+ ];
201
+ $params[ 'enabled' ] = !$params[ 'disabled' ];
202
+ $option = array_merge( [ 'rows' => '2' ], $option, $params );
203
+
204
+ // add strings
205
+ try {
206
+ $optStrings = $this->getMod()->getStrings()->getOptionStrings( $option[ 'key' ] );
207
+ if ( !is_array( $optStrings[ 'description' ] ) ) {
208
+ $optStrings[ 'description' ] = [ $optStrings[ 'description' ] ];
209
+ }
210
+ $option = Services::DataManipulation()->mergeArraysRecursive( $option, $optStrings );
211
+ }
212
+ catch ( \Exception $e ) {
213
+ }
214
+
215
+ return $this->addPerOptionCustomisation( $option );
216
+ }
217
+
218
+ private function addPerOptionCustomisation( array $option ) :array {
219
+ switch ( $option[ 'key' ] ) {
220
+
221
+ case 'file_locker':
222
+ if ( !Services::Data()->isWindows() ) {
223
+ error_log( var_export( $option[ 'value_options' ][ 'root_webconfig' ], true ) );
224
+ $option[ 'value_options' ][ 'root_webconfig' ] .= sprintf( ' (%s)', __( 'unavailable', 'wp-simple-firewall' ) );
225
+ error_log( var_export( $option, true ) );
226
+ }
227
+ break;
228
+
229
+ case 'visitor_address_source':
230
+ $newOptions = [];
231
+ $ipDetector = Services::IP()->getIpDetector();
232
+ foreach ( $option[ 'value_options' ] as $valKey => $source ) {
233
+ if ( $valKey == 'AUTO_DETECT_IP' ) {
234
+ $newOptions[ $valKey ] = $source;
235
+ }
236
+ else {
237
+ $IPs = implode( ', ', $ipDetector->getIpsFromSource( $source ) );
238
+ if ( !empty( $IPs ) ) {
239
+ $newOptions[ $valKey ] = sprintf( '%s (%s)', $source, $IPs );
240
+ }
241
+ }
242
+ }
243
+ $option[ 'value_options' ] = $newOptions;
244
+ break;
245
+
246
+ default:
247
+ break;
248
+ }
249
+ return $option;
250
+ }
251
+
252
+ public function setIsWhitelabelled( bool $isOrNot ) :self {
253
+ $this->isWhitelabelled = $isOrNot;
254
+ return $this;
255
+ }
256
+ }
src/lib/src/Modules/Base/UI.php CHANGED
@@ -10,140 +10,11 @@ class UI {
10
 
11
  use ModConsumer;
12
 
13
- /**
14
- * Will initiate the plugin options structure for use by the UI builder.
15
- * It doesn't set any values, just populates the array created in buildOptions()
16
- * with values stored.
17
- * It has to handle the conversion of stored values to data to be displayed to the user.
18
- */
19
- public function buildOptions() {
20
- $con = $this->getCon();
21
-
22
- $bPremiumEnabled = $con->isPremiumExtensionsEnabled();
23
- $bShowAdvanced = $con->getModule_Plugin()->isShowAdvanced();
24
-
25
- $opts = $this->getOptions();
26
- $options = $opts->getOptionsForPluginUse();
27
-
28
- foreach ( $options as $sectionKey => $sect ) {
29
-
30
- if ( !empty( $sect[ 'options' ] ) ) {
31
-
32
- foreach ( $sect[ 'options' ] as $optKey => $option ) {
33
- $option[ 'is_value_default' ] = ( $option[ 'value' ] === $option[ 'default' ] );
34
- $bIsPrem = $option[ 'premium' ] ?? false;
35
- $bIsAdv = $option[ 'advanced' ] ?? false;
36
- if ( ( !$bIsPrem || $bPremiumEnabled ) && ( !$bIsAdv || $bShowAdvanced ) ) {
37
- $sect[ 'options' ][ $optKey ] = $this->buildOptionForUi( $option );
38
- }
39
- else {
40
- unset( $sect[ 'options' ][ $optKey ] );
41
- }
42
- }
43
-
44
- if ( empty( $sect[ 'options' ] ) ) {
45
- unset( $options[ $sectionKey ] );
46
- }
47
- else {
48
- try {
49
- $sect = array_merge(
50
- $sect,
51
- $this->getMod()
52
- ->getStrings()
53
- ->getSectionStrings( $sect[ 'slug' ] )
54
- );
55
- }
56
- catch ( \Exception $e ) {
57
- }
58
- $options[ $sectionKey ] = $sect;
59
- }
60
-
61
- if ( isset( $options[ $sectionKey ] ) ) {
62
- $warning = [];
63
- if ( !$opts->isSectionReqsMet( $sect[ 'slug' ] ) ) {
64
- $warning[] = __( 'Unfortunately your WordPress and/or PHP versions are too old to support this feature.', 'wp-simple-firewall' );
65
- }
66
- $options[ $sectionKey ][ 'warnings' ] = array_merge(
67
- $warning,
68
- $this->getSectionWarnings( $sect[ 'slug' ] )
69
- );
70
- $options[ $sectionKey ][ 'notices' ] = $this->getSectionNotices( $sect[ 'slug' ] );
71
- }
72
- }
73
- }
74
-
75
- return $options;
76
- }
77
-
78
- /**
79
- * @param array $option
80
- * @return array
81
- */
82
- protected function buildOptionForUi( $option ) {
83
-
84
- $value = $option[ 'value' ];
85
-
86
- switch ( $option[ 'type' ] ) {
87
-
88
- case 'password':
89
- if ( !empty( $value ) ) {
90
- $value = '';
91
- }
92
- break;
93
-
94
- case 'array':
95
- if ( empty( $value ) || !is_array( $value ) ) {
96
- $value = [];
97
- }
98
-
99
- $option[ 'rows' ] = count( $value ) + 2;
100
- $value = stripslashes( implode( "\n", $value ) );
101
-
102
- break;
103
-
104
- case 'comma_separated_lists':
105
-
106
- $converted = [];
107
- if ( !empty( $value ) && is_array( $value ) ) {
108
- foreach ( $value as $page => $params ) {
109
- $converted[] = $page.', '.implode( ", ", $params );
110
- }
111
- }
112
- $option[ 'rows' ] = count( $converted ) + 1;
113
- $value = implode( "\n", $converted );
114
-
115
- break;
116
-
117
- case 'multiple_select':
118
- if ( !is_array( $value ) ) {
119
- $value = [];
120
- }
121
- break;
122
-
123
- case 'text':
124
- $value = stripslashes( $this->getMod()->getTextOpt( $option[ 'key' ] ) );
125
- break;
126
- }
127
-
128
- $params = [
129
- 'value' => is_scalar( $value ) ? esc_attr( $value ) : $value,
130
- 'disabled' => !$this->getCon()
131
- ->isPremiumActive() && ( isset( $option[ 'premium' ] ) && $option[ 'premium' ] ),
132
- ];
133
- $params[ 'enabled' ] = !$params[ 'disabled' ];
134
- $option = array_merge( [ 'rows' => 2 ], $option, $params );
135
-
136
- // add strings
137
- try {
138
- $aOptStrings = $this->getMod()->getStrings()->getOptionStrings( $option[ 'key' ] );
139
- if ( !is_array( $aOptStrings[ 'description' ] ) ) {
140
- $aOptStrings[ 'description' ] = [ $aOptStrings[ 'description' ] ];
141
- }
142
- $option = Services::DataManipulation()->mergeArraysRecursive( $option, $aOptStrings );
143
- }
144
- catch ( \Exception $e ) {
145
- }
146
- return $option;
147
  }
148
 
149
  public function buildSelectData_ModuleSettings() :array {
@@ -199,7 +70,7 @@ class UI {
199
  'data' => [
200
  'mod_slug' => $mod->getModSlug( true ),
201
  'mod_slug_short' => $mod->getModSlug( false ),
202
- 'all_options' => $this->buildOptions(),
203
  'xferable_opts' => ( new Shield\Modules\Plugin\Lib\ImportExport\Options\BuildTransferableOptions() )
204
  ->setMod( $mod )
205
  ->build(),
@@ -342,18 +213,11 @@ class UI {
342
  return false;
343
  }
344
 
345
- /**
346
- * @return string
347
- */
348
- protected function getHelpVideoId() {
349
- return $this->getOptions()->getDef( 'help_video_id' );
350
- }
351
-
352
- protected function getSectionNotices( string $section ) :array {
353
  return [];
354
  }
355
 
356
- protected function getSectionWarnings( string $section ) :array {
357
  return [];
358
  }
359
 
10
 
11
  use ModConsumer;
12
 
13
+ public function buildOptionsForStandardUI() :array {
14
+ return ( new Options\BuildForDisplay() )
15
+ ->setMod( $this->getMod() )
16
+ ->setIsWhitelabelled( $this->getCon()->getModule_SecAdmin()->getWhiteLabelController()->isEnabled() )
17
+ ->standard();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  }
19
 
20
  public function buildSelectData_ModuleSettings() :array {
70
  'data' => [
71
  'mod_slug' => $mod->getModSlug( true ),
72
  'mod_slug_short' => $mod->getModSlug( false ),
73
+ 'all_options' => $this->buildOptionsForStandardUI(),
74
  'xferable_opts' => ( new Shield\Modules\Plugin\Lib\ImportExport\Options\BuildTransferableOptions() )
75
  ->setMod( $mod )
76
  ->build(),
213
  return false;
214
  }
215
 
216
+ public function getSectionNotices( string $section ) :array {
 
 
 
 
 
 
 
217
  return [];
218
  }
219
 
220
+ public function getSectionWarnings( string $section ) :array {
221
  return [];
222
  }
223
 
src/lib/src/Modules/BaseShield/ModCon.php CHANGED
@@ -192,24 +192,16 @@ class ModCon extends Base\ModCon {
192
  ->isXmlrpcBypass();
193
  }
194
 
195
- /**
196
- * @param string[] $aArray
197
- * @param string $sPregReplacePattern
198
- * @return string[]
199
- */
200
- protected function cleanStringArray( $aArray, $sPregReplacePattern ) {
201
- $aCleaned = [];
202
- if ( !is_array( $aArray ) ) {
203
- return $aCleaned;
204
- }
205
 
206
- foreach ( $aArray as $nKey => $sVal ) {
207
- $sVal = preg_replace( $sPregReplacePattern, '', $sVal );
208
- if ( !empty( $sVal ) ) {
209
- $aCleaned[] = $sVal;
210
  }
211
  }
212
- return array_unique( array_filter( $aCleaned ) );
213
  }
214
 
215
  protected function getNamespaceRoots() :array {
192
  ->isXmlrpcBypass();
193
  }
194
 
195
+ public function cleanStringArray( array $arr, string $pregReplacePattern ) :array {
196
+ $cleaned = [];
 
 
 
 
 
 
 
 
197
 
198
+ foreach ( $arr as $val ) {
199
+ $val = preg_replace( $pregReplacePattern, '', $val );
200
+ if ( strlen( $val ) > 0 ) {
201
+ $cleaned[] = $val;
202
  }
203
  }
204
+ return $cleaned;
205
  }
206
 
207
  protected function getNamespaceRoots() :array {
src/lib/src/Modules/BaseShield/UI.php CHANGED
@@ -45,7 +45,8 @@ class UI extends Base\UI {
45
  'has_session' => $con->getModule_Sessions()
46
  ->getSessionCon()
47
  ->hasSession(),
48
- 'display_helpdesk_widget' => !$isWhitelabelled
 
49
  ],
50
  'hrefs' => [
51
  'aar_forget_key' => $isWhitelabelled ?
45
  'has_session' => $con->getModule_Sessions()
46
  ->getSessionCon()
47
  ->hasSession(),
48
+ 'display_helpdesk_widget' => !$isWhitelabelled,
49
+ 'is_whitelabelled' => $isWhitelabelled
50
  ],
51
  'hrefs' => [
52
  'aar_forget_key' => $isWhitelabelled ?
src/lib/src/Modules/HackGuard/Render/ScanResults/SectionThemes.php CHANGED
@@ -126,6 +126,7 @@ class SectionThemes extends SectionPluginThemesBase {
126
  'is_abandoned' => !empty( $abandoned ),
127
  'has_guard_files' => !empty( $guardFilesData ),
128
  'is_active' => $theme->active || $theme->is_parent,
 
129
  'is_vulnerable' => !empty( $vulnerabilities ),
130
  'is_wporg' => $theme->isWpOrg(),
131
  'is_child' => $theme->is_child,
@@ -144,6 +145,33 @@ class SectionThemes extends SectionPluginThemesBase {
144
  !$data[ 'flags' ][ 'is_active' ]
145
  || $data[ 'flags' ][ 'has_update' ]
146
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  return $data;
148
  }
149
  }
126
  'is_abandoned' => !empty( $abandoned ),
127
  'has_guard_files' => !empty( $guardFilesData ),
128
  'is_active' => $theme->active || $theme->is_parent,
129
+ 'is_ignored' => $theme->active || $theme->is_parent,
130
  'is_vulnerable' => !empty( $vulnerabilities ),
131
  'is_wporg' => $theme->isWpOrg(),
132
  'is_child' => $theme->is_child,
145
  !$data[ 'flags' ][ 'is_active' ]
146
  || $data[ 'flags' ][ 'has_update' ]
147
  );
148
+ if ( $theme->isWpOrg() && $data[ 'flags' ][ 'has_warning' ] && !$data[ 'flags' ][ 'has_update' ] ) {
149
+ $wpOrgThemes = implode( '|', array_map( function ( $ver ) {
150
+ return 'twenty'.$ver;
151
+ }, [
152
+ 'twentyseven',
153
+ 'twentysix',
154
+ 'twentyfive',
155
+ 'twentyfour',
156
+ 'twentythree',
157
+ 'twentytwo',
158
+ 'twentyone',
159
+ 'twenty',
160
+ 'nineteen',
161
+ 'seventeen',
162
+ 'sixteen',
163
+ 'fifteen',
164
+ 'fourteen',
165
+ 'thirteen',
166
+ 'twelve',
167
+ 'eleven',
168
+ 'ten',
169
+ ] ) );
170
+ if ( preg_match( sprintf( '#^%s$#', $wpOrgThemes ), strtolower( (string)$theme->slug ) ) ) {
171
+ $data[ 'flags' ][ 'has_warning' ] = false;
172
+ }
173
+ }
174
+
175
  return $data;
176
  }
177
  }
src/lib/src/Modules/HackGuard/UI.php CHANGED
@@ -189,18 +189,6 @@ class UI extends BaseShield\UI {
189
  return $scans;
190
  }
191
 
192
- /**
193
- * @param array $option
194
- * @return array
195
- */
196
- protected function buildOptionForUi( $option ) {
197
- $option = parent::buildOptionForUi( $option );
198
- if ( $option[ 'key' ] === 'file_locker' && !Services::Data()->isWindows() ) {
199
- $option[ 'value_options' ][ 'root_webconfig' ] .= sprintf( ' (%s)', __( 'unavailable', 'wp-simple-firewall' ) );
200
- }
201
- return $option;
202
- }
203
-
204
  protected function getFileLockerVars() :array {
205
  /** @var ModCon $mod */
206
  $mod = $this->getMod();
@@ -239,7 +227,7 @@ class UI extends BaseShield\UI {
239
  ];
240
  }
241
 
242
- protected function getSectionWarnings( string $section ) :array {
243
  $warnings = [];
244
 
245
  switch ( $section ) {
189
  return $scans;
190
  }
191
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  protected function getFileLockerVars() :array {
193
  /** @var ModCon $mod */
194
  $mod = $this->getMod();
227
  ];
228
  }
229
 
230
+ public function getSectionWarnings( string $section ) :array {
231
  $warnings = [];
232
 
233
  switch ( $section ) {
src/lib/src/Modules/IPs/AjaxHandler.php CHANGED
@@ -111,7 +111,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
111
  $msg = __( "This IP is reserved and can't be blacklisted.", 'wp-simple-firewall' );
112
  }
113
  else {
114
- $label = $formParams[ 'label' ] ?? '';
115
  $IP = null;
116
  switch ( $list ) {
117
  case $mod::LIST_MANUAL_WHITE:
@@ -119,7 +119,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
119
  $IP = ( new Shield\Modules\IPs\Lib\Ops\AddIp() )
120
  ->setMod( $mod )
121
  ->setIP( $ip )
122
- ->toManualWhitelist( (string)$label );
123
  }
124
  catch ( \Exception $e ) {
125
  }
@@ -130,7 +130,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
130
  $IP = ( new Shield\Modules\IPs\Lib\Ops\AddIp() )
131
  ->setMod( $mod )
132
  ->setIP( $ip )
133
- ->toManualBlacklist( (string)$label );
134
  }
135
  catch ( \Exception $e ) {
136
  }
111
  $msg = __( "This IP is reserved and can't be blacklisted.", 'wp-simple-firewall' );
112
  }
113
  else {
114
+ $label = (string)$formParams[ 'label' ] ?? '';
115
  $IP = null;
116
  switch ( $list ) {
117
  case $mod::LIST_MANUAL_WHITE:
119
  $IP = ( new Shield\Modules\IPs\Lib\Ops\AddIp() )
120
  ->setMod( $mod )
121
  ->setIP( $ip )
122
+ ->toManualWhitelist( $label );
123
  }
124
  catch ( \Exception $e ) {
125
  }
130
  $IP = ( new Shield\Modules\IPs\Lib\Ops\AddIp() )
131
  ->setMod( $mod )
132
  ->setIP( $ip )
133
+ ->toManualBlacklist( $label );
134
  }
135
  catch ( \Exception $e ) {
136
  }
src/lib/src/Modules/IPs/Lib/Ops/AddIp.php CHANGED
@@ -62,11 +62,10 @@ class AddIp {
62
  }
63
 
64
  /**
65
- * @param string $label
66
  * @return Databases\IPs\EntryVO|null
67
  * @throws \Exception
68
  */
69
- public function toManualBlacklist( $label = '' ) {
70
  /** @var ModCon $mod */
71
  $mod = $this->getMod();
72
  $srvIP = Services::IP();
@@ -126,11 +125,10 @@ class AddIp {
126
  }
127
 
128
  /**
129
- * @param string $label
130
  * @return Databases\IPs\EntryVO|null
131
  * @throws \Exception
132
  */
133
- public function toManualWhitelist( $label = '' ) {
134
  /** @var ModCon $mod */
135
  $mod = $this->getMod();
136
  $srvIP = Services::IP();
@@ -182,13 +180,10 @@ class AddIp {
182
  }
183
 
184
  /**
185
- * @param string $list
186
- * @param string $label
187
- * @param int|null $lastAccess
188
  * @return Databases\IPs\EntryVO|null
189
  * @throws \Exception
190
  */
191
- private function add( string $list, $label = '', $lastAccess = null ) {
192
  $IP = null;
193
 
194
  /** @var ModCon $mod */
@@ -201,16 +196,13 @@ class AddIp {
201
  $tmp = $dbh->getVo();
202
  $tmp->ip = $this->getIP();
203
  $tmp->list = $list;
204
- $tmp->label = empty( $label ) ? __( 'No Label', 'wp-simple-firewall' ) : trim( $label );
205
- if ( is_numeric( $lastAccess ) && $lastAccess > 0 ) {
206
- $tmp->last_access_at = $lastAccess;
207
- }
208
 
209
  if ( $dbh->getQueryInserter()->insert( $tmp ) ) {
210
  /** @var Databases\IPs\EntryVO $IP */
211
  $IP = $dbh->getQuerySelector()
212
- ->setWheresFromVo( $tmp )
213
- ->first();
214
  }
215
 
216
  if ( !$IP instanceof Databases\IPs\EntryVO ) {
62
  }
63
 
64
  /**
 
65
  * @return Databases\IPs\EntryVO|null
66
  * @throws \Exception
67
  */
68
+ public function toManualBlacklist( string $label = '' ) {
69
  /** @var ModCon $mod */
70
  $mod = $this->getMod();
71
  $srvIP = Services::IP();
125
  }
126
 
127
  /**
 
128
  * @return Databases\IPs\EntryVO|null
129
  * @throws \Exception
130
  */
131
+ public function toManualWhitelist( string $label = '' ) {
132
  /** @var ModCon $mod */
133
  $mod = $this->getMod();
134
  $srvIP = Services::IP();
180
  }
181
 
182
  /**
 
 
 
183
  * @return Databases\IPs\EntryVO|null
184
  * @throws \Exception
185
  */
186
+ private function add( string $list, string $label = '', int $accessAt = 0 ) {
187
  $IP = null;
188
 
189
  /** @var ModCon $mod */
196
  $tmp = $dbh->getVo();
197
  $tmp->ip = $this->getIP();
198
  $tmp->list = $list;
199
+ $tmp->label = (string)$label;
200
+ $tmp->last_access_at = $accessAt;
 
 
201
 
202
  if ( $dbh->getQueryInserter()->insert( $tmp ) ) {
203
  /** @var Databases\IPs\EntryVO $IP */
204
  $IP = $dbh->getQuerySelector()
205
+ ->byId( Services::WpDb()->getVar( 'SELECT LAST_INSERT_ID()' ) );
 
206
  }
207
 
208
  if ( !$IP instanceof Databases\IPs\EntryVO ) {
src/lib/src/Modules/IPs/UI.php CHANGED
@@ -71,7 +71,7 @@ class UI extends BaseShield\UI {
71
  ];
72
  }
73
 
74
- protected function getSectionWarnings( string $section ) :array {
75
  $warnings = [];
76
 
77
  /** @var Options $opts */
71
  ];
72
  }
73
 
74
+ public function getSectionWarnings( string $section ) :array {
75
  $warnings = [];
76
 
77
  /** @var Options $opts */
src/lib/src/Modules/IPs/WpCli/Add.php CHANGED
@@ -34,17 +34,15 @@ class Add extends BaseAddRemove {
34
  */
35
  public function cmdIpAdd( array $null, array $args ) {
36
 
37
- $label = $args[ 'label' ] ?? 'none';
38
-
39
  $adder = ( new Ops\AddIp() )
40
  ->setMod( $this->getMod() )
41
  ->setIP( $args[ 'ip' ] );
42
  try {
43
  if ( $args[ 'list' ] === 'white' ) {
44
- $adder->toManualWhitelist( $label );
45
  }
46
  else {
47
- $adder->toManualBlacklist( $label );
48
  }
49
  }
50
  catch ( \Exception $e ) {
34
  */
35
  public function cmdIpAdd( array $null, array $args ) {
36
 
 
 
37
  $adder = ( new Ops\AddIp() )
38
  ->setMod( $this->getMod() )
39
  ->setIP( $args[ 'ip' ] );
40
  try {
41
  if ( $args[ 'list' ] === 'white' ) {
42
+ $adder->toManualWhitelist( $args[ 'label' ] ?? '' );
43
  }
44
  else {
45
+ $adder->toManualBlacklist( $args[ 'label' ] ?? '' );
46
  }
47
  }
48
  catch ( \Exception $e ) {
src/lib/src/Modules/Integrations/UI.php CHANGED
@@ -7,7 +7,7 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Common
7
 
8
  class UI extends Modules\BaseShield\UI {
9
 
10
- protected function getSectionNotices( string $section ) :array {
11
  $notices = [];
12
 
13
  /** @var Modules\LoginGuard\Options $loginGuardOpts */
@@ -47,7 +47,7 @@ class UI extends Modules\BaseShield\UI {
47
  return $notices;
48
  }
49
 
50
- protected function getSectionWarnings( string $section ) :array {
51
  $warnings = [];
52
  $con = $this->getCon();
53
 
7
 
8
  class UI extends Modules\BaseShield\UI {
9
 
10
+ public function getSectionNotices( string $section ) :array {
11
  $notices = [];
12
 
13
  /** @var Modules\LoginGuard\Options $loginGuardOpts */
47
  return $notices;
48
  }
49
 
50
+ public function getSectionWarnings( string $section ) :array {
51
  $warnings = [];
52
  $con = $this->getCon();
53
 
src/lib/src/Modules/Lockdown/ModCon.php CHANGED
@@ -20,6 +20,9 @@ class ModCon extends BaseShield\ModCon {
20
  $this->cleanApiExclusions();
21
  }
22
 
 
 
 
23
  private function cleanApiExclusions() {
24
  /** @var Options $opts */
25
  $opts = $this->getOptions();
20
  $this->cleanApiExclusions();
21
  }
22
 
23
+ /**
24
+ * @deprecated 13.0.6
25
+ */
26
  private function cleanApiExclusions() {
27
  /** @var Options $opts */
28
  $opts = $this->getOptions();
src/lib/src/Modules/Lockdown/Options.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Lockdown;
4
 
@@ -9,29 +9,20 @@ class Options extends BaseShield\Options {
9
  /**
10
  * @return string[]
11
  */
12
- public function getRestApiAnonymousExclusions() {
13
- $ex = $this->getOpt( 'api_namespace_exclusions' );
14
- return array_merge( $this->getDef( 'default_restapi_exclusions' ), is_array( $ex ) ? $ex : [] );
15
  }
16
 
17
- /**
18
- * @return bool
19
- */
20
- public function isOptFileEditingDisabled() {
21
  return $this->isOpt( 'disable_file_editing', 'Y' );
22
  }
23
 
24
- /**
25
- * @return bool
26
- */
27
- public function isRestApiAnonymousAccessDisabled() {
28
  return $this->isOpt( 'disable_anonymous_restapi', 'Y' );
29
  }
30
 
31
- /**
32
- * @return bool
33
- */
34
- public function isXmlrpcDisabled() {
35
  return $this->isOpt( 'disable_xmlrpc', 'Y' );
36
  }
37
  }
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Lockdown;
4
 
9
  /**
10
  * @return string[]
11
  */
12
+ public function getRestApiAnonymousExclusions() :array {
13
+ $exc = apply_filters( 'shield/anonymous_rest_api_exclusions', $this->getOpt( 'api_namespace_exclusions' ) );
14
+ return $this->getMod()->cleanStringArray( $exc, '#[^a-z0-9_-]#i' );
15
  }
16
 
17
+ public function isOptFileEditingDisabled() :bool {
 
 
 
18
  return $this->isOpt( 'disable_file_editing', 'Y' );
19
  }
20
 
21
+ public function isRestApiAnonymousAccessDisabled() :bool {
 
 
 
22
  return $this->isOpt( 'disable_anonymous_restapi', 'Y' );
23
  }
24
 
25
+ public function isXmlrpcDisabled() :bool {
 
 
 
26
  return $this->isOpt( 'disable_xmlrpc', 'Y' );
27
  }
28
  }
src/lib/src/Modules/Lockdown/Strings.php CHANGED
@@ -84,8 +84,6 @@ class Strings extends Base\Strings {
84
  }
85
 
86
  /**
87
- * @param string $key
88
- * @return array
89
  * @throws \Exception
90
  */
91
  public function getOptionStrings( string $key ) :array {
@@ -110,29 +108,51 @@ class Strings extends Base\Strings {
110
  $name = __( 'Anonymous Rest API', 'wp-simple-firewall' );
111
  $summary = sprintf( __( 'Disable The %s System', 'wp-simple-firewall' ), __( 'Anonymous Rest API', 'wp-simple-firewall' ) );
112
  $description = [
113
- __( 'You can choose to completely disable anonymous access to the REST API.', 'wp-simple-firewall' ),
114
- sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( 'Enabling this option may break plugins that use the REST API for your site visitors.', 'wp-simple-firewall' ) )
 
115
  ];
116
  break;
117
 
118
  case 'api_namespace_exclusions' :
119
  $name = __( 'Rest API Exclusions', 'wp-simple-firewall' );
120
  $summary = __( 'Anonymous REST API Exclusions', 'wp-simple-firewall' );
121
- $description = __( 'Any namespaces provided here will be excluded from the Anonymous API restriction.', 'wp-simple-firewall' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  break;
123
 
124
  case 'disable_file_editing' :
125
  $name = __( 'Disable File Editing', 'wp-simple-firewall' );
126
  $summary = __( 'Disable Ability To Edit Files From Within WordPress', 'wp-simple-firewall' );
127
- $description = __( 'Removes the option to directly edit any files from within the WordPress admin area.', 'wp-simple-firewall' )
128
- .'<br />'.__( 'Equivalent to setting "DISALLOW_FILE_EDIT" to TRUE.', 'wp-simple-firewall' );
 
 
129
  break;
130
 
131
  case 'force_ssl_admin' :
132
  $name = __( 'Force SSL Admin', 'wp-simple-firewall' );
133
  $summary = __( 'Forces WordPress Admin Dashboard To Be Delivered Over SSL', 'wp-simple-firewall' );
134
- $description = __( 'Please only enable this option if you have a valid SSL certificate installed.', 'wp-simple-firewall' )
135
- .'<br />'.__( 'Equivalent to setting "FORCE_SSL_ADMIN" to TRUE.', 'wp-simple-firewall' );
 
 
136
  break;
137
 
138
  case 'hide_wordpress_generator_tag' :
@@ -155,8 +175,10 @@ class Strings extends Base\Strings {
155
  case 'block_author_discovery' :
156
  $name = __( 'Block Username Fishing', 'wp-simple-firewall' );
157
  $summary = __( 'Block the ability to discover WordPress usernames based on author IDs', 'wp-simple-firewall' );
158
- $description = sprintf( __( 'When enabled, any URL requests containing "%s" will be killed.', 'wp-simple-firewall' ), 'author=' )
159
- .'<br />'.sprintf( '%s - %s', __( 'Warning', 'wp-simple-firewall' ), __( 'Enabling this option may interfere with expected operations of your site.', 'wp-simple-firewall' ) );
 
 
160
  break;
161
 
162
  default:
84
  }
85
 
86
  /**
 
 
87
  * @throws \Exception
88
  */
89
  public function getOptionStrings( string $key ) :array {
108
  $name = __( 'Anonymous Rest API', 'wp-simple-firewall' );
109
  $summary = sprintf( __( 'Disable The %s System', 'wp-simple-firewall' ), __( 'Anonymous Rest API', 'wp-simple-firewall' ) );
110
  $description = [
111
+ __( 'You can completely disable anonymous access to the REST API.', 'wp-simple-firewall' ),
112
+ sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( 'Enabling this option may break plugins that use the REST API for your site visitors.', 'wp-simple-firewall' ) ),
113
+ __( 'Use the exclusions option to allow anonymous access to specific API endpoints.', 'wp-simple-firewall' ),
114
  ];
115
  break;
116
 
117
  case 'api_namespace_exclusions' :
118
  $name = __( 'Rest API Exclusions', 'wp-simple-firewall' );
119
  $summary = __( 'Anonymous REST API Exclusions', 'wp-simple-firewall' );
120
+ $description = [
121
+ __( 'These REST API namespaces will be excluded from the Anonymous API restriction.', 'wp-simple-firewall' ),
122
+ sprintf( __( 'Some plugins (e.g. %s) use the REST API anonymously so you need to provide exclusions for them to work correctly.', 'wp-simple-firewall' ),
123
+ 'Contact Form 7' ),
124
+ __( "Please contact the developer of a plugin to ask them for their REST API namespace if you need it." ),
125
+ __( 'Some common namespaces' ).':',
126
+ ];
127
+
128
+ $defaultEx = [
129
+ 'contact-form-7' => 'Contact Form 7',
130
+ 'tribe' => 'The Events Calendar',
131
+ 'jetpack' => 'JetPack',
132
+ 'woocommerce' => 'WooCommerce',
133
+ 'wpstatistics' => 'WP Statistics',
134
+ ];
135
+ foreach ( $defaultEx as $defNamespace => $defName ) {
136
+ $description[] = sprintf( '<code>%s</code> - %s', $defNamespace, $defName );
137
+ }
138
  break;
139
 
140
  case 'disable_file_editing' :
141
  $name = __( 'Disable File Editing', 'wp-simple-firewall' );
142
  $summary = __( 'Disable Ability To Edit Files From Within WordPress', 'wp-simple-firewall' );
143
+ $description = [
144
+ __( 'Removes the option to directly edit any files from within the WordPress admin area.', 'wp-simple-firewall' ),
145
+ __( 'Equivalent to setting "DISALLOW_FILE_EDIT" to TRUE.', 'wp-simple-firewall' )
146
+ ];
147
  break;
148
 
149
  case 'force_ssl_admin' :
150
  $name = __( 'Force SSL Admin', 'wp-simple-firewall' );
151
  $summary = __( 'Forces WordPress Admin Dashboard To Be Delivered Over SSL', 'wp-simple-firewall' );
152
+ $description = [
153
+ __( 'Please only enable this option if you have a valid SSL certificate installed.', 'wp-simple-firewall' ),
154
+ __( 'Equivalent to setting "FORCE_SSL_ADMIN" to TRUE.', 'wp-simple-firewall' )
155
+ ];
156
  break;
157
 
158
  case 'hide_wordpress_generator_tag' :
175
  case 'block_author_discovery' :
176
  $name = __( 'Block Username Fishing', 'wp-simple-firewall' );
177
  $summary = __( 'Block the ability to discover WordPress usernames based on author IDs', 'wp-simple-firewall' );
178
+ $description = [
179
+ sprintf( __( 'When enabled, any URL requests containing "%s" will be killed.', 'wp-simple-firewall' ), 'author=' ),
180
+ sprintf( '%s - %s', __( 'Warning', 'wp-simple-firewall' ), __( 'Enabling this option may interfere with expected operations of your site.', 'wp-simple-firewall' ) )
181
+ ];
182
  break;
183
 
184
  default:
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php CHANGED
@@ -130,6 +130,7 @@ class MfaProfilesController {
130
  },
131
  $mfaCon->getProvidersForUser( $user, true )
132
  );
 
133
 
134
  echo $mfaCon->getMod()->renderTemplate( '/admin/user/profile/mfa/remove_for_other_user.twig', [
135
  'flags' => [
130
  },
131
  $mfaCon->getProvidersForUser( $user, true )
132
  );
133
+ $this->rendered = true;
134
 
135
  echo $mfaCon->getMod()->renderTemplate( '/admin/user/profile/mfa/remove_for_other_user.twig', [
136
  'flags' => [
src/lib/src/Modules/LoginGuard/UI.php CHANGED
@@ -9,7 +9,7 @@ use FernleafSystems\Wordpress\Services\Services;
9
 
10
  class UI extends BaseShield\UI {
11
 
12
- protected function getSectionNotices( string $section ) :array {
13
  /** @var Options $opts */
14
  $opts = $this->getOptions();
15
 
@@ -31,7 +31,7 @@ class UI extends BaseShield\UI {
31
  return $notices;
32
  }
33
 
34
- protected function getSectionWarnings( string $section ) :array {
35
  $con = $this->getCon();
36
  /** @var Options $opts */
37
  $opts = $this->getOptions();
9
 
10
  class UI extends BaseShield\UI {
11
 
12
+ public function getSectionNotices( string $section ) :array {
13
  /** @var Options $opts */
14
  $opts = $this->getOptions();
15
 
31
  return $notices;
32
  }
33
 
34
+ public function getSectionWarnings( string $section ) :array {
35
  $con = $this->getCon();
36
  /** @var Options $opts */
37
  $opts = $this->getOptions();
src/lib/src/Modules/Plugin/Lib/Debug/Collate.php CHANGED
@@ -117,11 +117,11 @@ class Collate {
117
 
118
  $data = [];
119
 
120
- foreach ( $oWpPlugins->getPluginsAsVo() as $oVO ) {
121
- if ( $filterByActive === $oVO->active ) {
122
- $data[ $oVO->Name ] = sprintf( '%s / %s / %s',
123
- $oVO->Version, $oVO->active ? 'Active' : 'Deactivated',
124
- $oVO->hasUpdate() ? 'Update Available' : 'No Update'
125
  );
126
  }
127
  }
@@ -268,7 +268,7 @@ class Collate {
268
 
269
  private function getServiceIPs() :array {
270
  return [
271
- 'ips'=>var_export(Services::ServiceProviders()::GetProviderIPs(),true),
272
 
273
  ];
274
  }
@@ -276,6 +276,15 @@ class Collate {
276
  private function getWordPressSummary() :array {
277
  $WP = Services::WpGeneral();
278
  $data = [
 
 
 
 
 
 
 
 
 
279
  'URL - Home' => $WP->getHomeUrl(),
280
  'URL - Site' => $WP->getWpUrl(),
281
  'WP' => $WP->getVersion( true ),
@@ -289,11 +298,6 @@ class Collate {
289
  sprintf( 'User: <code>%s</code>', DB_USER ),
290
  sprintf( 'Prefix: <code>%s</code>', Services::WpDb()->getPrefix() ),
291
  ],
292
- ];
293
- if ( $WP->isClassicPress() ) {
294
- $data[ 'ClassicPress' ] = $WP->getVersion();
295
- }
296
-
297
- return $data;
298
  }
299
  }
117
 
118
  $data = [];
119
 
120
+ foreach ( $oWpPlugins->getPluginsAsVo() as $VO ) {
121
+ if ( $filterByActive === $VO->active ) {
122
+ $data[ $VO->Name ] = sprintf( '%s / %s / %s',
123
+ $VO->Version, $VO->active ? 'Active' : 'Deactivated',
124
+ $VO->hasUpdate() ? 'Update Available' : 'No Update'
125
  );
126
  }
127
  }
268
 
269
  private function getServiceIPs() :array {
270
  return [
271
+ 'ips' => var_export( Services::ServiceProviders()::GetProviderIPs(), true ),
272
 
273
  ];
274
  }
276
  private function getWordPressSummary() :array {
277
  $WP = Services::WpGeneral();
278
  $data = [
279
+ 'URL - Home' => $WP->getHomeUrl(),
280
+ 'URL - Site' => $WP->getWpUrl(),
281
+ 'WP' => $WP->getVersion( true ),
282
+ ];
283
+ if ( $WP->isClassicPress() ) {
284
+ $data[ 'ClassicPress' ] = $WP->getVersion();
285
+ }
286
+
287
+ return array_merge( $data, [
288
  'URL - Home' => $WP->getHomeUrl(),
289
  'URL - Site' => $WP->getWpUrl(),
290
  'WP' => $WP->getVersion( true ),
298
  sprintf( 'User: <code>%s</code>', DB_USER ),
299
  sprintf( 'Prefix: <code>%s</code>', Services::WpDb()->getPrefix() ),
300
  ],
301
+ ] );
 
 
 
 
 
302
  }
303
  }
src/lib/src/Modules/Plugin/UI.php CHANGED
@@ -72,25 +72,11 @@ class UI extends BaseShield\UI {
72
  protected function buildOptionForUi( $option ) {
73
  $option = parent::buildOptionForUi( $option );
74
  if ( $option[ 'key' ] === 'visitor_address_source' ) {
75
- $newOptions = [];
76
- $ipDetector = Services::IP()->getIpDetector();
77
- foreach ( $option[ 'value_options' ] as $valKey => $source ) {
78
- if ( $valKey == 'AUTO_DETECT_IP' ) {
79
- $newOptions[ $valKey ] = $source;
80
- }
81
- else {
82
- $IPs = implode( ', ', $ipDetector->getIpsFromSource( $source ) );
83
- if ( !empty( $IPs ) ) {
84
- $newOptions[ $valKey ] = sprintf( '%s (%s)', $source, $IPs );
85
- }
86
- }
87
- }
88
- $option[ 'value_options' ] = $newOptions;
89
  }
90
  return $option;
91
  }
92
 
93
- protected function getSectionWarnings( string $section ) :array {
94
  /** @var ModCon $mod */
95
  $mod = $this->getMod();
96
  $opts = $this->getOptions();
72
  protected function buildOptionForUi( $option ) {
73
  $option = parent::buildOptionForUi( $option );
74
  if ( $option[ 'key' ] === 'visitor_address_source' ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
76
  return $option;
77
  }
78
 
79
+ public function getSectionWarnings( string $section ) :array {
80
  /** @var ModCon $mod */
81
  $mod = $this->getMod();
82
  $opts = $this->getOptions();
src/lib/src/Modules/SecurityAdmin/UI.php CHANGED
@@ -6,7 +6,7 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
6
 
7
  class UI extends BaseShield\UI {
8
 
9
- protected function getSectionWarnings( string $section ) :array {
10
  /** @var ModCon $mod */
11
  $mod = $this->getMod();
12
 
6
 
7
  class UI extends BaseShield\UI {
8
 
9
+ public function getSectionWarnings( string $section ) :array {
10
  /** @var ModCon $mod */
11
  $mod = $this->getMod();
12
 
src/lib/src/Modules/Traffic/UI.php CHANGED
@@ -38,7 +38,7 @@ class UI extends BaseShield\UI {
38
  );
39
  }
40
 
41
- protected function getSectionWarnings( string $section ) :array {
42
  /** @var Options $opts */
43
  $opts = $this->getOptions();
44
 
38
  );
39
  }
40
 
41
+ public function getSectionWarnings( string $section ) :array {
42
  /** @var Options $opts */
43
  $opts = $this->getOptions();
44
 
src/lib/src/Tables/Render/WpListTable/AdminNotes.php CHANGED
@@ -4,12 +4,8 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\WpListTable;
4
 
5
  class AdminNotes extends Base {
6
 
7
- /**
8
- * @param array $aItem
9
- * @return string
10
- */
11
- public function column_note( $aItem ) {
12
- return $aItem[ 'note' ].$this->buildActions( [ $this->getActionButton_Delete( $aItem[ 'id' ] ) ] );
13
  }
14
 
15
  /**
4
 
5
  class AdminNotes extends Base {
6
 
7
+ public function column_note( array $item ) :string {
8
+ return esc_html( $item[ 'note' ] ).$this->buildActions( [ $this->getActionButton_Delete( $item[ 'id' ] ) ] );
 
 
 
 
9
  }
10
 
11
  /**
src/lib/src/Tables/Render/WpListTable/IpBase.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\WpListTable;
4
 
@@ -8,6 +8,10 @@ class IpBase extends Base {
8
  return $item[ 'ip' ].$this->buildActions( [ $this->getActionButton_Delete( $item[ 'id' ] ) ] );
9
  }
10
 
 
 
 
 
11
  public function get_columns() {
12
  return [
13
  'ip' => __( 'IP Address' ),
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\WpListTable;
4
 
8
  return $item[ 'ip' ].$this->buildActions( [ $this->getActionButton_Delete( $item[ 'id' ] ) ] );
9
  }
10
 
11
+ public function column_label( array $item ) :string {
12
+ return esc_html( empty( $item[ 'label' ] ) ? __( 'No Label', 'wp-simple-firewall' ) : $item[ 'label' ] );
13
+ }
14
+
15
  public function get_columns() {
16
  return [
17
  'ip' => __( 'IP Address' ),
src/lib/src/Tables/Render/WpListTable/IpBlack.php CHANGED
@@ -7,20 +7,20 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
7
  class IpBlack extends IpBase {
8
 
9
  /**
10
- * @param array $aItem
11
  * @return string
12
  */
13
- public function column_details( $aItem ) {
14
- $bAutoBlock = $aItem[ 'list' ] === ModCon::LIST_AUTO_BLACK;
15
  return implode( '<br/>', [
16
- sprintf( '%s: %s', __( 'Blocked', 'wp-simple-firewall' ), $aItem[ 'blocked' ] ),
17
  sprintf( '%s / %s',
18
- $aItem[ 'is_range' ] ? __( 'IP Range', 'wp-simple-firewall' ) : __( 'Single IP', 'wp-simple-firewall' ),
19
- $bAutoBlock ? __( 'Automatic', 'wp-simple-firewall' ) : __( 'Manual', 'wp-simple-firewall' )
20
  ),
21
  sprintf( '%s - %s',
22
- sprintf( _n( '%s Offense', '%s Offenses', $aItem[ 'transgressions' ], 'wp-simple-firewall' ), $aItem[ 'transgressions' ] ),
23
- sprintf( '%s: %s', __( 'Last Access', 'wp-simple-firewall' ), $aItem[ 'last_trans_at' ] )
24
  ),
25
  ] );
26
  }
7
  class IpBlack extends IpBase {
8
 
9
  /**
10
+ * @param array $item
11
  * @return string
12
  */
13
+ public function column_details( $item ) {
14
+ $autoBlock = $item[ 'list' ] === ModCon::LIST_AUTO_BLACK;
15
  return implode( '<br/>', [
16
+ sprintf( '%s: %s', __( 'Blocked', 'wp-simple-firewall' ), $item[ 'blocked' ] ),
17
  sprintf( '%s / %s',
18
+ $item[ 'is_range' ] ? __( 'IP Range', 'wp-simple-firewall' ) : __( 'Single IP', 'wp-simple-firewall' ),
19
+ $autoBlock ? __( 'Automatic', 'wp-simple-firewall' ) : __( 'Manual', 'wp-simple-firewall' )
20
  ),
21
  sprintf( '%s - %s',
22
+ sprintf( _n( '%s Offense', '%s Offenses', $item[ 'transgressions' ], 'wp-simple-firewall' ), $item[ 'transgressions' ] ),
23
+ sprintf( '%s: %s', __( 'Last Access', 'wp-simple-firewall' ), $item[ 'last_trans_at' ] )
24
  ),
25
  ] );
26
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Core/General.php CHANGED
@@ -332,7 +332,19 @@ class General {
332
  $this->sWpVersion = $wp_version;
333
  }
334
  }
335
- return ( $bIgnoreClassicpress || !$this->isClassicPress() ) ? $this->sWpVersion : \classicpress_version();
 
 
 
 
 
 
 
 
 
 
 
 
336
  }
337
 
338
  public function getWordpressIsAtLeastVersion( string $version, bool $ignoreCP = true ) :bool {
332
  $this->sWpVersion = $wp_version;
333
  }
334
  }
335
+
336
+ if ( $bIgnoreClassicpress || !$this->isClassicPress() ) {
337
+ $version = $this->sWpVersion;
338
+ }
339
+ else {
340
+ $version = \classicpress_version();
341
+ preg_match( '#^(\d+(?:\.\d)+)(.*)$#', $version, $matches );
342
+ if ( !empty( $matches[ 2 ] ) ) {
343
+ $version = $matches[ 1 ];
344
+ }
345
+ }
346
+
347
+ return $version;
348
  }
349
 
350
  public function getWordpressIsAtLeastVersion( string $version, bool $ignoreCP = true ) :bool {
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Hashes/ClassicPress.php CHANGED
@@ -4,10 +4,6 @@ namespace FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Has
4
 
5
  use FernleafSystems\Wordpress\Services;
6
 
7
- /**
8
- * Class ClassicPress
9
- * @package FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Hashes
10
- */
11
  class ClassicPress extends AssetHashesBase {
12
 
13
  const TYPE = 'classicpress';
4
 
5
  use FernleafSystems\Wordpress\Services;
6
 
 
 
 
 
7
  class ClassicPress extends AssetHashesBase {
8
 
9
  const TYPE = 'classicpress';
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/WpOrg/Cp/Download.php CHANGED
@@ -28,16 +28,15 @@ class Download {
28
  }
29
 
30
  /**
31
- * @param $version
32
  * @return string|null
33
  */
34
- private function getZipDownloadUrl( $version ) {
35
  $url = null;
36
  $versions = @json_decode( Services::HttpRequest()->getContent( Repo::GetUrlForVersions() ), true );
37
 
38
  if ( is_array( $versions ) ) {
39
  foreach ( $versions as $version ) {
40
- if ( $version[ 'tag_name' ] == $version ) {
41
  $url = $version[ 'zipball_url' ];
42
  break;
43
  }
28
  }
29
 
30
  /**
 
31
  * @return string|null
32
  */
33
+ private function getZipDownloadUrl( string $versionToFind ) {
34
  $url = null;
35
  $versions = @json_decode( Services::HttpRequest()->getContent( Repo::GetUrlForVersions() ), true );
36
 
37
  if ( is_array( $versions ) ) {
38
  foreach ( $versions as $version ) {
39
+ if ( $version[ 'tag_name' ] == $versionToFind ) {
40
  $url = $version[ 'zipball_url' ];
41
  break;
42
  }
templates/twig/components/options_form/option.twig CHANGED
@@ -14,11 +14,9 @@
14
  title="{{ strings.opt_info_helpdesk }}">
15
  <span class="dashicons dashicons-editor-help"></span>
16
  </a>
17
- {% else %}
18
- {% if aOption.link_info %}
19
  <a href="{{ aOption.link_info }}" class="option_link_info d-inline-block" target="_blank"
20
  title="{{ strings.opt_info_helpdesk }}"></a>
21
- {% endif %}
22
  {% endif %}
23
  </span>
24
 
@@ -183,22 +181,19 @@
183
  </div>
184
 
185
  <div class="mt-3 text-left text-nowrap">
186
- {% if aOption.link_info or aOption.beacon_id|default(false) %}
187
-
188
- {% if aOption.beacon_id|default(false) %}
189
- <a href="javascript:{}" data-beacon-article-sidebar="{{ aOption.beacon_id }}"
190
- title="{{ strings.opt_info_helpdesk }}">{{ strings.more_info }}</a>
191
 
192
- {% else %}
193
- <a href="{{ aOption.link_info }}" target="_blank"
194
- title="{{ strings.opt_info_helpdesk }}">{{ strings.more_info }}</a>
195
- {% endif %}
196
 
197
- {% if aOption.link_blog %}
198
- <span class="m-1">&vert;</span>
199
- <a href="{{ aOption.link_blog }}" target="_blank"
200
- title="{{ strings.opt_info_blog }}">{{ strings.blog }}</a>
201
- {% endif %}
202
  {% endif %}
203
 
204
  {% if flags.is_wpcli %}
14
  title="{{ strings.opt_info_helpdesk }}">
15
  <span class="dashicons dashicons-editor-help"></span>
16
  </a>
17
+ {% elseif aOption.link_info %}
 
18
  <a href="{{ aOption.link_info }}" class="option_link_info d-inline-block" target="_blank"
19
  title="{{ strings.opt_info_helpdesk }}"></a>
 
20
  {% endif %}
21
  </span>
22
 
181
  </div>
182
 
183
  <div class="mt-3 text-left text-nowrap">
184
+ {% if aOption.beacon_id|default(false) %}
185
+ <a href="javascript:{}" data-beacon-article-sidebar="{{ aOption.beacon_id }}"
186
+ title="{{ strings.opt_info_helpdesk }}">{{ strings.more_info }}</a>
 
 
187
 
188
+ {% elseif aOption.link_info %}
189
+ <a href="{{ aOption.link_info }}" target="_blank"
190
+ title="{{ strings.opt_info_helpdesk }}">{{ strings.more_info }}</a>
191
+ {% endif %}
192
 
193
+ {% if aOption.link_blog %}
194
+ <span class="m-1">&vert;</span>
195
+ <a href="{{ aOption.link_blog }}" target="_blank"
196
+ title="{{ strings.opt_info_blog }}">{{ strings.blog }}</a>
 
197
  {% endif %}
198
 
199
  {% if flags.is_wpcli %}