--- a/wp-simple-firewall/icwp-wpsf.php
+++ b/wp-simple-firewall/icwp-wpsf.php
@@ -3,7 +3,7 @@
* Plugin Name: Shield Security
* Plugin URI: https://clk.shldscrty.com/2f
* Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
- * Version: 21.0.9
+ * Version: 21.0.10
* Text Domain: wp-simple-firewall
* Domain Path: /languages
* Author: Shield Security
--- a/wp-simple-firewall/src/lib/functions/functions.php
+++ b/wp-simple-firewall/src/lib/functions/functions.php
@@ -1,39 +1,39 @@
-<?php declare( strict_types=1 );
-
-use FernleafSystemsWordpressPluginShieldFunctions;
-
-if ( function_exists( 'shield_security_get_plugin' ) ) {
- return;
-}
-
-function shield_security_get_plugin() :ICWP_WPSF_Shield_Security {
- return Functionsget_plugin();
-}
-
-function shield_get_visitor_scores( $IP = null ) :array {
- return Functionsget_visitor_scores( $IP );
-}
-
-function shield_get_visitor_score( $IP = null ) :int {
- return Functionsget_visitor_score( $IP );
-}
-
-/**
- * @param null $IP - defaults to current visitor
- * @throws Exception
- */
-function shield_test_ip_is_bot( $IP = null ) :bool {
- return Functionstest_ip_is_bot( $IP );
-}
-
-function shield_get_ip_state( string $ip = '' ) :string {
- return Functionsget_ip_state( $ip );
-}
-
-function shield_fire_event( string $event ) {
- Functionsfire_event( $event );
-}
-
-function shield_start_scans( array $scans ) {
- Functionsstart_scans( $scans );
+<?php declare( strict_types=1 );
+
+use FernleafSystemsWordpressPluginShieldFunctions;
+
+if ( function_exists( 'shield_security_get_plugin' ) ) {
+ return;
+}
+
+function shield_security_get_plugin() :ICWP_WPSF_Shield_Security {
+ return Functionsget_plugin();
+}
+
+function shield_get_visitor_scores( $IP = null ) :array {
+ return Functionsget_visitor_scores( $IP );
+}
+
+function shield_get_visitor_score( $IP = null ) :int {
+ return Functionsget_visitor_score( $IP );
+}
+
+/**
+ * @param null $IP - defaults to current visitor
+ * @throws Exception
+ */
+function shield_test_ip_is_bot( $IP = null ) :bool {
+ return Functionstest_ip_is_bot( $IP );
+}
+
+function shield_get_ip_state( string $ip = '' ) :string {
+ return Functionsget_ip_state( $ip );
+}
+
+function shield_fire_event( string $event ) {
+ Functionsfire_event( $event );
+}
+
+function shield_start_scans( array $scans ) {
+ Functionsstart_scans( $scans );
}
No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/BaseAction.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/BaseAction.php
@@ -154,14 +154,10 @@
* @return self For method chaining
*/
public function setActionOverride( string $overrideKey, $value ) :self {
- // Initialize action_overrides array if it doesn't exist
- if ( !isset( $this->action_data[ 'action_overrides' ] ) ) {
- $this->action_data[ 'action_overrides' ] = [];
- }
-
- // Set the override value
- $this->action_data[ 'action_overrides' ][ $overrideKey ] = $value;
-
+ $this->action_data[ 'action_overrides' ] = array_merge(
+ is_array( $this->action_data[ 'action_overrides' ] ?? null ) ? $this->action_data[ 'action_overrides' ] : [],
+ [ $overrideKey => $value ]
+ );
return $this;
}
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/MfaLoginFlowBase.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/MfaLoginFlowBase.php
@@ -0,0 +1,20 @@
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
+
+use FernleafSystemsWordpressPluginShieldActionRouterActionsTraitsAuthNotRequired;
+use FernleafSystemsWordpressPluginShieldActionRouterActionsTraitsLoginWpUserConsumer;
+
+/**
+ * Base class for MFA actions that run during the login flow.
+ *
+ * These actions:
+ * - Do NOT require authentication (user is in the middle of logging in)
+ * - REQUIRE a valid login_nonce tied to the target user
+ * - Use login_wp_user parameter with login_nonce validation
+ */
+abstract class MfaLoginFlowBase extends BaseAction {
+
+ use AuthNotRequired;
+ use LoginWpUserConsumer;
+}
No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/MfaPasskeyAuthenticationStart.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/MfaPasskeyAuthenticationStart.php
@@ -2,27 +2,22 @@
namespace FernleafSystemsWordpressPluginShieldActionRouterActions;
-use FernleafSystemsWordpressPluginShieldActionRouterActionsTraitsAuthNotRequired;
+use FernleafSystemsWordpressPluginShieldActionRouterExceptionsActionException;
use FernleafSystemsWordpressPluginShieldModulesLoginGuardLibTwoFactorProviderPasskey;
-class MfaPasskeyAuthenticationStart extends MfaUserConfigBase {
-
- use AuthNotRequired;
+class MfaPasskeyAuthenticationStart extends MfaLoginFlowBase {
public const SLUG = 'mfa_passkey_auth_start';
protected function exec() {
-
$response = [
'success' => false,
'page_reload' => false
];
- $user = $this->getActiveWPUser();
- if ( empty( $user ) ) {
- $response[ 'message' ] = __( 'User must be logged-in.', 'wp-simple-firewall' );
- }
- else {
+ try {
+ $user = $this->getLoginWPUser();
+
$available = self::con()->comps->mfa->getProvidersAvailableToUser( $user );
/** @var Passkey $provider */
$provider = $available[ Passkey::ProviderSlug() ] ?? null;
@@ -31,19 +26,27 @@
$response[ 'message' ] = __( "Passkeys aren't available for this user.", 'wp-simple-firewall' );
}
else {
- try {
- $response = [
- 'success' => true,
- 'challenge' => $provider->startNewAuth(),
- 'page_reload' => false
- ];
- }
- catch ( Exception $e ) {
- $response[ 'message' ] = __( "There was a problem preparing the Passkey Auth Challenge.", 'wp-simple-firewall' );
- }
+ $response = [
+ 'success' => true,
+ 'challenge' => $provider->startNewAuth(),
+ 'page_reload' => false
+ ];
}
}
+ catch ( ActionException $e ) {
+ $response[ 'message' ] = $e->getMessage();
+ }
+ catch ( Exception $e ) {
+ $response[ 'message' ] = __( 'There was a problem preparing the Passkey Auth Challenge.', 'wp-simple-firewall' );
+ }
$this->response()->action_response_data = $response;
}
+
+ protected function getRequiredDataKeys() :array {
+ return [
+ 'login_wp_user',
+ 'login_nonce',
+ ];
+ }
}
No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/MfaPasskeyAuthenticationVerify.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/MfaPasskeyAuthenticationVerify.php
@@ -8,14 +8,14 @@
/**
* Not currently used
*/
-class MfaPasskeyAuthenticationVerify extends MfaUserConfigBase {
+class MfaPasskeyAuthenticationVerify extends MfaLoginFlowBase {
use AuthNotRequired;
public const SLUG = 'mfa_passkey_auth_verify';
protected function exec() {
- $available = self::con()->comps->mfa->getProvidersAvailableToUser( $this->getActiveWPUser() );
+ $available = self::con()->comps->mfa->getProvidersAvailableToUser( $this->getLoginWPUser() );
/** @var Passkey $provider */
$provider = $available[ Passkey::ProviderSlug() ];
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/IpAnalyse/Base.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/IpAnalyse/Base.php
@@ -9,9 +9,7 @@
class Base extends RenderBaseRender {
protected function getRequiredDataKeys() :array {
- return [
- 'ip'
- ];
+ return [ 'ip' ];
}
protected function getTimeAgo( int $ts ) :string {
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/BaseComponent.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/BaseComponent.php
@@ -0,0 +1,17 @@
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouterActionsRenderComponentsScansItemAnalysis;
+
+use FernleafSystemsWordpressPluginShieldActionRouterActionsRenderComponentsScansBaseScans;
+use FernleafSystemsWordpressPluginShieldScansAfsResultItem;
+
+abstract class BaseComponent extends BaseScans {
+
+ protected function getScanItem() :ResultItem {
+ return $this->action_data[ 'scan_item' ];
+ }
+
+ protected function getRequiredDataKeys() :array {
+ return [ 'scan_item' ];
+ }
+}
No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/Container.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/Container.php
@@ -2,16 +2,31 @@
namespace FernleafSystemsWordpressPluginShieldActionRouterActionsRenderComponentsScansItemAnalysis;
+use FernleafSystemsWordpressPluginShieldActionRouterActionsRenderComponentsScansBaseScans;
+use FernleafSystemsWordpressPluginShieldActionRouterExceptionsActionException;
+use FernleafSystemsWordpressPluginShieldModulesHackGuardScanResultsRetrieveRetrieveItems;
+use FernleafSystemsWordpressPluginShieldScansAfsResultItem;
use FernleafSystemsWordpressServicesServices;
-class Container extends Base {
+class Container extends BaseScans {
public const SLUG = 'scanitemanalysis_container';
public const TEMPLATE = '/wpadmin_pages/insights/scans/modal/scan_item_analysis/modal_content.twig';
protected function getRenderData() :array {
$con = self::con();
- $item = $this->getScanItem();
+ try {
+ /** @var ResultItem $item */
+ $item = ( new RetrieveItems() )->byID( (int)$this->action_data[ 'rid' ] );
+ }
+ catch ( Exception $e ) {
+ throw new ActionException( 'Not a valid scan item record' );
+ }
+
+ $fragment = $item->path_fragment;
+ if ( empty( $fragment ) ) {
+ throw new ActionException( 'Non-file scan items are not supported yet.' );
+ }
$fullPath = empty( $item->path_full ) ? path_join( ABSPATH, $item->path_fragment ) : $item->path_full;
return [
@@ -55,4 +70,10 @@
],
];
}
+
+ protected function getRequiredDataKeys() :array {
+ return [
+ 'rid'
+ ];
+ }
}
No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/Content.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/Content.php
@@ -6,7 +6,7 @@
use FernleafSystemsWordpressServicesServices;
use FernleafSystemsWordpressServicesUtilitiesFileConvertLineEndings;
-class Content extends Base {
+class Content extends BaseComponent {
public const SLUG = 'scanitemanalysis_content';
public const TEMPLATE = '/wpadmin_pages/insights/scans/modal/scan_item_analysis/file_content.twig';
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/Diff.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/Diff.php
@@ -8,7 +8,7 @@
use FernleafSystemsWordpressServicesUtilitiesIntegrationsWpHashesUtilDiff as DiffUtil;
use FernleafSystemsWordpressServicesUtilitiesWpOrg;
-class Diff extends Base {
+class Diff extends BaseComponent {
public const SLUG = 'scanitemanalysis_diff';
public const TEMPLATE = '/wpadmin_pages/insights/scans/modal/scan_item_analysis/file_diff.twig';
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/History.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/History.php
@@ -5,7 +5,7 @@
use FernleafSystemsWordpressPluginShieldModulesHackGuardScanResultsRetrieveRetrieveItems;
use FernleafSystemsWordpressServicesServices;
-class History extends Base {
+class History extends BaseComponent {
public const SLUG = 'scanitemanalysis_history';
public const TEMPLATE = '/wpadmin_pages/insights/scans/modal/scan_item_analysis/file_history.twig';
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/Info.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/Info.php
@@ -8,7 +8,7 @@
use FernleafSystemsWordpressServicesServices;
use FernleafSystemsWordpressServicesUtilitiesWpOrgWpRepo;
-class Info extends Base {
+class Info extends BaseComponent {
public const SLUG = 'scanitemanalysis_info';
public const TEMPLATE = '/wpadmin_pages/insights/scans/modal/scan_item_analysis/file_info.twig';
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/Malai.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Scans/ItemAnalysis/Malai.php
@@ -6,7 +6,7 @@
use FernleafSystemsWordpressServicesServices;
use FernleafSystemsWordpressServicesUtilitiesFilePaths;
-class Malai extends Base {
+class Malai extends BaseComponent {
public const SLUG = 'scanitemanalysis_malai';
public const TEMPLATE = '/wpadmin_pages/insights/scans/modal/scan_item_analysis/file_malai.twig';
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Traffic/TrafficLiveLogs.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Traffic/TrafficLiveLogs.php
@@ -12,7 +12,7 @@
protected function getRenderData() :array {
$logLoader = new LoadRequestLogs();
- $logLoader->limit = (int)$this->action_data[ 'limit' ] ?? 200;
+ $logLoader->limit = (int)( $this->action_data[ 'limit' ] ?? 200 );
$logLoader->offset = 0;
$logLoader->order_by = 'id';
$logLoader->order_dir = 'DESC';
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/UserMfa/ConfigEdit.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/UserMfa/ConfigEdit.php
@@ -3,6 +3,7 @@
namespace FernleafSystemsWordpressPluginShieldActionRouterActionsRenderComponentsUserMfa;
use FernleafSystemsWordpressPluginShieldActionRouterActionsTraitsSecurityAdminNotRequired;
+use FernleafSystemsWordpressPluginShieldActionRouterExceptionsActionException;
use FernleafSystemsWordpressServicesServices;
class ConfigEdit extends UserMfaBase {
@@ -15,7 +16,15 @@
protected function getRenderData() :array {
$con = self::con();
- $user = Services::WpUsers()->getUserById( (int)$this->action_data[ 'user_id' ] );
+
+ $WPU = Services::WpUsers();
+ $currentUser = $WPU->getCurrentWpUser();
+ $requestedUserID = (int)( $this->action_data[ 'user_id' ] ?? 0 );
+ if ( $requestedUserID > 0 && $currentUser->ID !== $requestedUserID && !$WPU->isUserAdmin( $currentUser ) ) {
+ throw new ActionException( __( 'Invalid profile request.', 'wp-simple-firewall' ) );
+ }
+
+ $user = $requestedUserID > 0 ? $WPU->getUserById( $requestedUserID ) : $currentUser;
$providers = array_map(
fn( $provider ) => $provider->getProviderName(),
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/UserMfa/ConfigForm.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/UserMfa/ConfigForm.php
@@ -3,6 +3,7 @@
namespace FernleafSystemsWordpressPluginShieldActionRouterActionsRenderComponentsUserMfa;
use FernleafSystemsWordpressPluginShieldActionRouterActionsTraitsAnyUserAuthRequired;
+use FernleafSystemsWordpressPluginShieldActionRouterExceptionsActionException;
use FernleafSystemsWordpressServicesServices;
class ConfigForm extends UserMfaBase {
@@ -22,7 +23,13 @@
protected function getRenderData() :array {
$WPU = Services::WpUsers();
- $user = $WPU->getUserById( (int)$this->action_data[ 'user_id' ] ?? $WPU->getCurrentWpUserId() );
+ $currentUser = $WPU->getCurrentWpUser();
+ $requestedUserID = (int)( $this->action_data[ 'user_id' ] ?? 0 );
+ if ( $requestedUserID > 0 && $currentUser->ID !== $requestedUserID && !self::con()->this_req->is_security_admin ) {
+ throw new ActionException( __( 'Invalid profile request.', 'wp-simple-firewall' ) );
+ }
+
+ $user = $requestedUserID > 0 ? $WPU->getUserById( $requestedUserID ) : $currentUser;
$providerRenders = array_map(
fn( $provider ) => $provider->renderUserProfileConfigFormField(),
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Users/ProfileSuspend.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/Components/Users/ProfileSuspend.php
@@ -3,6 +3,7 @@
namespace FernleafSystemsWordpressPluginShieldActionRouterActionsRenderComponentsUsers;
use FernleafSystemsWordpressPluginShieldActionRouterActionsTraitsSecurityAdminNotRequired;
+use FernleafSystemsWordpressPluginShieldActionRouterExceptionsActionException;
use FernleafSystemsWordpressServicesServices;
/**
@@ -16,9 +17,17 @@
public const TEMPLATE = '/admin/user/profile/suspend.twig';
protected function getRenderData() :array {
+ $con = self::con();
+
$WPU = Services::WpUsers();
- $editUser = $WPU->getUserById( $this->action_data[ 'user_id' ] );
- $meta = self::con()->user_metas->for( $editUser );
+ $currentUser = $WPU->getCurrentWpUser();
+ $requestedUserID = (int)( $this->action_data[ 'user_id' ] ?? 0 );
+ if ( $requestedUserID > 0 && $currentUser->ID !== $requestedUserID && !$WPU->isUserAdmin( $currentUser ) ) {
+ throw new ActionException( __( 'Invalid profile request.', 'wp-simple-firewall' ) );
+ }
+
+ $editUser = $requestedUserID > 0 ? $WPU->getUserById( $requestedUserID ) : $currentUser;
+ $meta = $con->user_metas->for( $editUser );
return [
'strings' => [
'title' => __( 'Suspend Account', 'wp-simple-firewall' ),
@@ -29,7 +38,7 @@
Services::WpGeneral()->getTimeStringForDisplay( $meta->record->hard_suspended_at ) ),
],
'flags' => [
- 'can_suspend' => self::con()->comps->user_suspend->canManuallySuspend()
+ 'can_suspend' => $con->comps->user_suspend->canManuallySuspend()
|| ( !$WPU->isUserAdmin( $editUser ) && $WPU->isUserAdmin() ),
'is_suspended' => $meta->record->hard_suspended_at > 0
],
@@ -40,8 +49,6 @@
}
protected function getRequiredDataKeys() :array {
- return [
- 'user_id'
- ];
+ return [ 'user_id' ];
}
}
No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/FullPage/Mfa/BaseLoginIntentPage.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Render/FullPage/Mfa/BaseLoginIntentPage.php
@@ -16,7 +16,9 @@
use ActionsTraitsAuthNotRequired;
public function getLoginIntentJavascript() :array {
- $userID = (int)$this->action_data[ 'user_id' ];
+ $userID = (int)$this->action_data[ 'user_id' ] ?? 0;
+ $loginNonce = (string)$this->action_data[ 'plain_login_nonce' ] ?? '';
+
$prov = self::con()->comps->mfa->getProvidersActiveForUser(
Services::WpUsers()->getUserById( $userID )
);
@@ -24,11 +26,12 @@
return [
'ajax' => [
'passkey_auth_start' => ActionData::Build( MfaPasskeyAuthenticationStart::class, true, [
- 'active_wp_user' => $userID,
+ 'login_wp_user' => $userID,
+ 'login_nonce' => $loginNonce,
] ),
'email_code_send' => ActionData::Build( MfaEmailSendIntent::class, true, [
'wp_user_id' => $userID,
- 'login_nonce' => $this->action_data[ 'plain_login_nonce' ],
+ 'login_nonce' => $loginNonce,
'redirect_to' => esc_url_raw( $this->action_data[ 'redirect_to' ] ?? '' ),
] ),
],
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Traits/ActiveWpUserConsumer.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Traits/ActiveWpUserConsumer.php
@@ -4,11 +4,17 @@
use FernleafSystemsWordpressServicesServices;
+/**
+ * Trait for actions that operate on the current authenticated user's profile.
+ *
+ * SECURITY: This trait always returns the current logged-in user.
+ * For login flow actions (unauthenticated), use LoginWpUserConsumer instead.
+ */
trait ActiveWpUserConsumer {
public function getActiveWPUser() :?WP_User {
- $user = Services::WpUsers()->getUserById( (int)$this->action_data[ 'active_wp_user' ] ?? null );
- return $user instanceof WP_User ? $user : Services::WpUsers()->getCurrentWpUser();
+ $user = Services::WpUsers()->getCurrentWpUser();
+ return $user instanceof WP_User ? $user : null;
}
public function hasActiveWPUser() :bool {
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Traits/LoginWpUserConsumer.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Actions/Traits/LoginWpUserConsumer.php
@@ -0,0 +1,51 @@
+<?php declare( strict_types=1 );
+
+namespace FernleafSystemsWordpressPluginShieldActionRouterActionsTraits;
+
+use FernleafSystemsWordpressPluginShieldActionRouterExceptionsActionException;
+use FernleafSystemsWordpressServicesServices;
+
+/**
+ * Trait for actions that operate during the login flow (user NOT authenticated).
+ *
+ * SECURITY: This trait requires a valid login_nonce to identify the user.
+ * The login_nonce is created when the user successfully enters their password
+ * and is tied to their user ID. This prevents attackers from targeting
+ * arbitrary users during the login flow.
+ */
+trait LoginWpUserConsumer {
+
+ /**
+ * @throws ActionException
+ */
+ public function getLoginWPUser() :WP_User {
+ $userID = (int)$this->action_data[ 'login_wp_user' ] ?? 0;
+ $loginNonce = (string)$this->action_data[ 'login_nonce' ] ?? '';
+
+ if ( $userID < 1 || empty( $loginNonce ) ) {
+ throw new ActionException( __( 'Invalid login session.', 'wp-simple-firewall' ) );
+ }
+
+ $user = Services::WpUsers()->getUserById( $userID );
+ if ( !$user instanceof WP_User ) {
+ throw new ActionException( __( 'User not found.', 'wp-simple-firewall' ) );
+ }
+
+ // Validate the login_nonce belongs to this user
+ if ( !self::con()->comps->mfa->verifyLoginNonce( $user, $loginNonce ) ) {
+ throw new ActionException( __( 'Invalid or expired login session.', 'wp-simple-firewall' ) );
+ }
+
+ return $user;
+ }
+
+ public function hasValidLoginSession() :bool {
+ try {
+ $this->getLoginWPUser();
+ return true;
+ }
+ catch ( ActionException $e ) {
+ return false;
+ }
+ }
+}
No newline at end of file
--- a/wp-simple-firewall/src/lib/src/ActionRouter/Constants.php
+++ b/wp-simple-firewall/src/lib/src/ActionRouter/Constants.php
@@ -106,7 +106,6 @@
ActionsPluginSetOpt::class,
ActionsToolPurgeProviderIPs::class,
ActionsTrafficLogTableAction::class,
- ActionsUserSessionDelete::class,
ActionsDebugSimplePluginTests::class,
ActionsFullPageDisplayDisplayBlockPage::class,
--- a/wp-simple-firewall/src/lib/src/Modules/IPs/Lib/AutoUnblock/AutoUnblockMagicLink.php
+++ b/wp-simple-firewall/src/lib/src/Modules/IPs/Lib/AutoUnblock/AutoUnblockMagicLink.php
@@ -35,7 +35,7 @@
EmailVO::Factory(
$user->user_email,
__( 'Automatic IP Unblock Request', 'wp-simple-firewall' ),
- $con->action_router->render( UnblockMagicLink::SLUG, [
+ $con->action_router->render( UnblockMagicLink::class, [
'home_url' => Services::WpGeneral()->getHomeUrl(),
'ip' => $con->this_req->ip,
'user_id' => $user->ID,
--- a/wp-simple-firewall/src/lib/src/Modules/Integrations/Lib/MainWP/Server/ExtensionSettingsPage.php
+++ b/wp-simple-firewall/src/lib/src/Modules/Integrations/Lib/MainWP/Server/ExtensionSettingsPage.php
@@ -28,14 +28,12 @@
'handles' => [
'mainwp_server',
],
- 'data' => function () {
- return [
- 'ajax' => [
- 'site_action' => ActionData::Build( MainWPServerActionsMainwpServerClientActionHandler::class ),
- 'ext_table' => ActionData::Build( MainWPMainwpExtensionTableSites::class ),
- ],
- ];
- },
+ 'data' => fn() => [
+ 'ajax' => [
+ 'site_action' => ActionData::Build( MainWPServerActionsMainwpServerClientActionHandler::class ),
+ 'ext_table' => ActionData::Build( MainWPMainwpExtensionTableSites::class ),
+ ],
+ ],
];
return $components;
} );
--- a/wp-simple-firewall/src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php
+++ b/wp-simple-firewall/src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php
@@ -65,7 +65,7 @@
add_action( 'edit_user_profile', function ( $user ) {
if ( $user instanceof WP_User ) {
$this->rendered = true;
- echo self::con()->action_router->render( ActionsRenderComponentsUserMfaConfigEdit::SLUG, [
+ echo self::con()->action_router->render( ActionsRenderComponentsUserMfaConfigEdit::class, [
'user_id' => $user->ID
] );
}
--- a/wp-simple-firewall/unsupported.php
+++ b/wp-simple-firewall/unsupported.php
@@ -1,32 +1,34 @@
-<?php
-
-add_action( 'admin_notices', 'icwp_wpsf_unsupported_php' );
-add_action( 'network_admin_notices', 'icwp_wpsf_unsupported_php' );
-
-function icwp_wpsf_unsupported_php() {
- global $sIcwpWpsfPluginFile;
- $text = array(
- 'Sorry, your website runs an incredibly old version of PHP that Shield Security no longer supports, as of Shield v9.0',
- "Your PHP no longer gets upgrades and it's difficult to maintain code for.",
- 'We recommend that you contact your website hosting provider on how to upgrade to at least PHP 7.4'
- );
- echo sprintf(
- '<div class="error"><h4>%s</h4><p>%s</p>' .
- '<p><a href="%s" target="_blank" style="font-weight: bolder">%s</a> ' .
- '/ <a href="%s">%s</a></p></div>',
-
- sprintf( 'Shield Security Plugin - Unsupported PHP Version: %s', PHP_VERSION ),
- implode( '<br/>', $text ),
- 'https://clk.shldscrty.com/dl',
- 'Click here for more info',
- add_query_arg(
- array(
- 'action' => 'deactivate',
- 'plugin' => urlencode( $sIcwpWpsfPluginFile ),
- '_wpnonce' => wp_create_nonce( 'deactivate-plugin_'.$sIcwpWpsfPluginFile )
- ),
- self_admin_url( 'plugins.php' )
- ),
- 'Or, deactivate the Shield Security plugin for now'
- );
+<?php
+
+if ( !defined( 'ABSPATH' ) ) { exit(); }
+
+add_action( 'admin_notices', 'icwp_wpsf_unsupported_php' );
+add_action( 'network_admin_notices', 'icwp_wpsf_unsupported_php' );
+
+function icwp_wpsf_unsupported_php() {
+ global $sIcwpWpsfPluginFile;
+ $text = array(
+ 'Sorry, your website runs an incredibly old version of PHP that Shield Security no longer supports, as of Shield v9.0',
+ "Your PHP no longer gets upgrades and it's difficult to maintain code for.",
+ 'We recommend that you contact your website hosting provider on how to upgrade to at least PHP 7.4'
+ );
+ echo sprintf(
+ '<div class="error"><h4>%s</h4><p>%s</p>' .
+ '<p><a href="%s" target="_blank" style="font-weight: bolder">%s</a> ' .
+ '/ <a href="%s">%s</a></p></div>',
+
+ sprintf( 'Shield Security Plugin - Unsupported PHP Version: %s', PHP_VERSION ),
+ implode( '<br/>', $text ),
+ 'https://clk.shldscrty.com/dl',
+ 'Click here for more info',
+ add_query_arg(
+ array(
+ 'action' => 'deactivate',
+ 'plugin' => urlencode( $sIcwpWpsfPluginFile ),
+ '_wpnonce' => wp_create_nonce( 'deactivate-plugin_'.$sIcwpWpsfPluginFile )
+ ),
+ self_admin_url( 'plugins.php' )
+ ),
+ 'Or, deactivate the Shield Security plugin for now'
+ );
}
No newline at end of file