From ccf5e61a075c35d24befc175994b5cb8957ca322 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Wed, 26 Aug 2026 21:45:53 +0000
Subject: [PATCH] =Extra JVB() calls replaced, minor tweaks

---
 inc/rest/routes/LoginRoutes.php |  139 +++++++++++----------------------------------
 1 files changed, 35 insertions(+), 104 deletions(-)

diff --git a/inc/rest/routes/LoginRoutes.php b/inc/rest/routes/LoginRoutes.php
index 47fa450..67f209d 100644
--- a/inc/rest/routes/LoginRoutes.php
+++ b/inc/rest/routes/LoginRoutes.php
@@ -159,15 +159,8 @@
 			error_log('[handleLogin]Turnstile succeeded');
 		}
 
-		// Attempt authentication
-		$user = wp_authenticate($email, $password);
-
+		$user = $this->login($email, $password, $remember);
 		if (is_wp_error($user)) {
-			$this->auditLog('login_failed', [
-				'email' => $email,
-				'error' => $user->get_error_code(),
-			]);
-
 			return $this->error(
 				$this->getLoginErrorMessage($user),
 				$user->get_error_code(),
@@ -175,21 +168,6 @@
 			);
 		}
 
-		// Set auth cookie
-		wp_clear_auth_cookie();
-		wp_set_current_user($user->ID);
-		wp_set_auth_cookie($user->ID, $remember);
-
-		// Store session fingerprint
-		$this->storeSessionFingerprint($user->ID, $request);
-
-		do_action('wp_login', $user->user_login, $user);
-
-		$this->auditLog('login_success', [
-			'user_id' => $user->ID,
-			'email' => $email,
-		]);
-
 		// Get redirect URL
 		$redirect = $this->getRedirectUrl($user, $redirect_to);
 
@@ -201,6 +179,40 @@
 		]);
 	}
 
+	public function login(string $email, string $password, bool $remember, ?WP_REST_Request $request = null):WP_User|WP_Error
+	{
+		// Attempt authentication
+		$user = wp_authenticate($email, $password);
+
+		if (is_wp_error($user)) {
+			$this->auditLog('login_failed', [
+				'email' => $email,
+				'error' => $user->get_error_code(),
+			]);
+
+			return $user;
+		}
+
+		// Set auth cookie
+		wp_clear_auth_cookie();
+		wp_set_current_user($user->ID);
+		wp_set_auth_cookie($user->ID, $remember);
+
+		// Store session fingerprint
+		if ($request) {
+			$this->storeSessionFingerprint($user->ID, $request);
+		}
+
+
+		do_action('wp_login', $user->user_login, $user);
+
+		$this->auditLog('login_success', [
+			'user_id' => $user->ID,
+			'email' => $email,
+		]);
+		return $user;
+	}
+
 	/**
 	 * Handle user registration
 	 */
@@ -506,87 +518,6 @@
 		]);
 	}
 
-	/************************************************************
-	 * SESSION FINGERPRINTING
-	 *
-	 * Detects session hijacking by validating that session hasn't
-	 * moved to a different device/network. Uses IP class (not full IP)
-	 * to allow mobile network changes without breaking sessions.
-	 ************************************************************/
-
-	/**
-	 * Store session fingerprint for hijacking detection
-	 */
-	protected function storeSessionFingerprint(int $user_id, WP_REST_Request $request): void
-	{
-		if (!defined('JVB_SESSION_FINGERPRINT') || !JVB_SESSION_FINGERPRINT) {
-			return;
-		}
-
-		$fingerprint = $this->generateSessionFingerprint($request);
-		update_user_meta($user_id, BASE . 'session_fingerprint', $fingerprint);
-		update_user_meta($user_id, BASE . 'session_timestamp', time());
-	}
-
-	/**
-	 * Generate session fingerprint for hijacking detection
-	 */
-	protected function generateSessionFingerprint(WP_REST_Request $request): string
-	{
-		return hash('sha256', implode('|', [
-			$request->get_header('User-Agent') ?? '',
-			// Use IP class instead of full IP to allow for mobile network changes
-			$this->getIPClass(
-				$request->get_header('X-Forwarded-For')
-					?: $request->get_header('X-Real-IP')
-					?: $_SERVER['REMOTE_ADDR'] ?? ''
-			)
-		]));
-	}
-
-	/**
-	 * Get IP class (first 3 octets) for session validation
-	 * Allows for minor IP changes (common with mobile networks)
-	 */
-	protected function getIPClass(string $ip): string
-	{
-		$parts = explode('.', $ip);
-		return implode('.', array_slice($parts, 0, 3));
-	}
-
-	/**
-	 * Validate session fingerprint against stored value
-	 */
-	protected function validateSessionFingerprint(int $user_id, WP_REST_Request $request): bool
-	{
-		// Only enforce if enabled in config
-		if (!defined('JVB_SESSION_FINGERPRINT') || !JVB_SESSION_FINGERPRINT) {
-			return true;
-		}
-
-		$stored = get_user_meta($user_id, BASE . 'session_fingerprint', true);
-		$current = $this->generateSessionFingerprint($request);
-
-		if (empty($stored)) {
-			// First request - store fingerprint
-			update_user_meta($user_id, BASE . 'session_fingerprint', $current);
-			update_user_meta($user_id, BASE . 'session_timestamp', time());
-			return true;
-		}
-
-		// Compare using timing-safe comparison
-		return hash_equals($stored, $current);
-	}
-
-	/**
-	 * Clear session fingerprint (call on logout)
-	 */
-	protected function clearSessionFingerprint(int $user_id): void
-	{
-		delete_user_meta($user_id, BASE . 'session_fingerprint');
-		delete_user_meta($user_id, BASE . 'session_timestamp');
-	}
-
 	/**************************************************************
 	 * HELPERS
 	 **************************************************************/

--
Gitblit v1.10.0