From 235ce5716edc2f7cbe80fdccf26eac7269587839 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Mon, 08 Jun 2026 04:38:18 +0000
Subject: [PATCH] =FavouritesManager.php and FavouritesRoutes.php fixes. Moving all logic to FavouritesManager.php. Still some left to do
---
assets/js/concise/AuthManager.js | 183 ++++++++++++++++-----------------------------
1 files changed, 65 insertions(+), 118 deletions(-)
diff --git a/assets/js/concise/AuthManager.js b/assets/js/concise/AuthManager.js
index dfad8bf..12a4a5f 100644
--- a/assets/js/concise/AuthManager.js
+++ b/assets/js/concise/AuthManager.js
@@ -17,8 +17,6 @@
this.nonces = {};
this.subscribers = new Set();
- this.storageKey = 'jvb_auth_state';
- this.cacheMetaKey = 'jvb_auth_meta';
this.cacheExpiry = 5 * 60 * 1000; // 5 minutes
this.init();
@@ -28,36 +26,23 @@
* Initialize authentication
*/
async init() {
- if (this.isAuthenticating) {
- // Wait for existing auth to complete
- return new Promise(resolve => {
- const checkAuth = setInterval(() => {
- if (this.initialized) {
- clearInterval(checkAuth);
- resolve();
- }
- }, 50);
- });
- }
-
+ if (this.isAuthenticating) return;
this.isAuthenticating = true;
try {
- // Check if we have cached auth and cookie hasn't changed
- const cached = this.getCachedAuth();
- if (cached) {
- this.setAuthData(cached);
+ // Inlined by wp_localize_script — zero cost
+ if (typeof jvbAuth !== 'undefined') {
+ this.setAuthData(jvbAuth);
this.initialized = true;
this.isAuthenticating = false;
- this.notify('auth-loaded', { fromCache: true });
+ this.notify('auth-loaded', { fromCache: false });
return;
}
- // Fetch fresh auth data
+ // Fallback: REST fetch (Redis-backed, fast server-side)
await this.fetchAuth();
} catch (error) {
- console.error('Failed to initialize auth:', error);
this.clearAuthData();
this.initialized = true;
this.isAuthenticating = false;
@@ -66,37 +51,70 @@
}
/**
+ * Refresh nonce if authentication fails
+ */
+ async refreshNonce(action = 'wp_rest') {
+ try {
+ await this.fetchAuth();
+ return this.getNonce(action);
+ } catch (error) {
+ console.error('Failed to refresh nonce:', error);
+ return null;
+ }
+ }
+
+ /**
+ * Fetch with automatic nonce refresh on auth failure
+ * Use this for all authenticated API requests
+ */
+ async fetch(url, options = {}) {
+ const attempt = async (retryCount = 0) => {
+ const isFormData = options.body instanceof FormData;
+
+ const headers = {
+ ...(!isFormData && { 'Content-Type': 'application/json' }),
+ ...options.headers,
+ 'X-WP-Nonce': this.getNonce()
+ };
+
+ const response = await fetch(url, {
+ ...options,
+ credentials: 'same-origin',
+ headers
+ });
+
+ if ((response.status === 403 || response.status === 401) && retryCount === 0) {
+ const result = await response.clone().json();
+ if (result.code === 'rest_cookie_invalid_nonce' || result.message?.includes('Cookie check')) {
+ console.log('Nonce invalid, refreshing auth...');
+ await this.refresh();
+ return attempt(retryCount + 1);
+ }
+ }
+
+ return response;
+ };
+
+ return attempt();
+ }
+
+ /**
* Fetch authentication status from API
*/
async fetchAuth() {
const response = await fetch(`${jvbSettings.api}auth/status`, {
method: 'GET',
credentials: 'same-origin',
- headers: {
- 'Content-Type': 'application/json'
- }
+ headers: { 'Content-Type': 'application/json' }
});
- if (!response.ok) {
- throw new Error('Auth check failed');
- }
+ if (!response.ok) throw new Error('Auth check failed');
const authData = await response.json();
-
- // Check if session changed (e.g., logout in another tab)
- const cachedMeta = sessionStorage.getItem(this.cacheMetaKey);
- if (cachedMeta) {
- const meta = JSON.parse(cachedMeta);
- if (meta.session_id && meta.session_id !== authData.session_id) {
- this.clearCachedAuth();
- this.notify('session-changed', {});
- }
- }
-
- this.cacheAuth(authData);
this.setAuthData(authData);
this.initialized = true;
this.isAuthenticating = false;
+
this.notify('auth-loaded', { fromCache: false });
}
@@ -104,9 +122,17 @@
* Set authentication data
*/
setAuthData(authData) {
+ const wasAuthenticated = this.initialized && this.authenticated;
+
this.authenticated = authData.authenticated || false;
this.user = authData.user || false;
this.nonces = authData.nonces || {};
+ console.log(this.nonces);
+
+ // Session expired — was logged in, now isn't
+ if (wasAuthenticated && !this.authenticated) {
+ window.location.href = `/login?redirect_to=${encodeURIComponent(window.location.href)}`;
+ }
}
/**
@@ -116,62 +142,8 @@
this.authenticated = false;
this.user = null;
this.nonces = {};
-
- sessionStorage.removeItem(this.storageKey);
- sessionStorage.removeItem(this.cacheMetaKey );
}
- /**
- * Get cached auth data (only if cookie matches)
- */
- getCachedAuth() {
- try {
- const cachedAuth = sessionStorage.getItem(this.storageKey);
- const cacheMeta = sessionStorage.getItem(this.cacheMetaKey);
-
- if (!cachedAuth || !cacheMeta) {
- return null;
- }
-
- const meta = JSON.parse(cacheMeta);
- const authData = JSON.parse(cachedAuth);
-
- // Time-based expiry (nonce freshness)
- if (Date.now() - meta.timestamp > this.cacheExpiry) {
- this.clearCachedAuth();
- return null;
- }
-
- // Session changed (login/logout in another tab/window)
- // We'll verify this on next fetch and clear if mismatched
-
- return authData;
-
- } catch (error) {
- console.error('Error reading cached auth:', error);
- return null;
- }
- }
-
- /**
- * Cache auth data in sessionStorage
- */
- cacheAuth(authData) {
- try {
- sessionStorage.setItem(this.storageKey, JSON.stringify(authData));
- sessionStorage.setItem(this.cacheMetaKey, JSON.stringify({
- session_id: authData.session_id || null,
- timestamp: Date.now()
- }));
- } catch (error) {
- console.error('Error caching auth:', error);
- }
- }
-
- clearCachedAuth() {
- sessionStorage.removeItem(this.storageKey);
- sessionStorage.removeItem(this.cacheMetaKey);
- }
/**
* Refresh authentication (force new fetch)
@@ -211,21 +183,13 @@
* Handle successful login (call after login completes)
*/
async handleLogin(authData = null) {
- // Clear old cache
- sessionStorage.removeItem(this.storageKey);
- sessionStorage.removeItem(this.cacheMetaKey);
-
- // If auth data provided, use it directly
if (authData) {
- this.cacheAuth(authData);
this.setAuthData(authData);
this.initialized = true;
this.isAuthenticating = false;
this.notify('auth-loaded', { fromCache: false, fromLogin: true });
return;
}
-
- // Otherwise fetch fresh (for backward compatibility)
await this.refresh();
}
@@ -267,23 +231,6 @@
});
}
- /**
- * Wait for auth to be ready
- */
- ready() {
- if (this.initialized) {
- return Promise.resolve();
- }
-
- return new Promise(resolve => {
- const unsubscribe = this.subscribe((event) => {
- if (event === 'auth-loaded' || event === 'auth-error') {
- unsubscribe();
- resolve();
- }
- });
- });
- }
}
// Initialize global instance
--
Gitblit v1.10.0