Harden auth cookies and fix native schema for event creation
Mirror to GitHub / mirror (push) Successful in 45s
Test and Lint / backend-test (push) Successful in 1m37s
Test and Lint / frontend-test (push) Successful in 2m8s
Version and Release / version-bump (push) Successful in 1m0s
Version and Release / trigger-drone (push) Successful in 3s
Mirror to GitHub / mirror (push) Successful in 45s
Test and Lint / backend-test (push) Successful in 1m37s
Test and Lint / frontend-test (push) Successful in 2m8s
Version and Release / version-bump (push) Successful in 1m0s
Version and Release / trigger-drone (push) Successful in 3s
This commit is contained in:
+5
-100
@@ -1,9 +1,4 @@
|
||||
import axios, { AxiosHeaders } from 'axios';
|
||||
import Cookies from 'js-cookie';
|
||||
|
||||
// Cookie keys
|
||||
export const ADMIN_TOKEN_KEY = 'admin_token';
|
||||
export const GALLERY_TOKEN_KEY = 'gallery_token';
|
||||
import axios from 'axios';
|
||||
|
||||
// Maintenance mode callback
|
||||
let maintenanceModeCallback: ((enabled: boolean) => void) | null = null;
|
||||
@@ -18,80 +13,12 @@ export const api = axios.create({
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
withCredentials: false, // Ensure we're not relying on cookies
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
// Request interceptor to add auth token
|
||||
// Request interceptor: drop Content-Type for FormData payloads so the browser can set boundaries
|
||||
api.interceptors.request.use(
|
||||
(config) => {
|
||||
// Don't process if headers are already set by the component
|
||||
const existingAuth = config.headers?.['Authorization'] || config.headers?.get?.('Authorization');
|
||||
|
||||
// If authorization is already set by the component, don't override it
|
||||
if (existingAuth) {
|
||||
return config;
|
||||
}
|
||||
|
||||
// Check if it's an admin route or gallery route
|
||||
const isAdminRoute = config.url?.includes('/admin');
|
||||
|
||||
if (isAdminRoute) {
|
||||
const token = Cookies.get(ADMIN_TOKEN_KEY);
|
||||
if (token) {
|
||||
if (!config.headers) {
|
||||
config.headers = {};
|
||||
}
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
} else {
|
||||
// For gallery routes, try to extract slug from the request URL first
|
||||
const galleryMatch = config.url?.match(/gallery\/([^\/]+)/);
|
||||
|
||||
if (galleryMatch && galleryMatch[1]) {
|
||||
const galleryIdOrSlug = galleryMatch[1];
|
||||
// Remove any query parameters from the slug
|
||||
const cleanIdOrSlug = galleryIdOrSlug.split('?')[0];
|
||||
|
||||
// Check if it's a numeric ID (for upload endpoints)
|
||||
let token = null;
|
||||
if (/^\d+$/.test(cleanIdOrSlug)) {
|
||||
// It's an event ID - try to find the token from current page slug
|
||||
const pathParts = window.location.pathname.split('/');
|
||||
if (pathParts[1] === 'gallery' && pathParts[2]) {
|
||||
const gallerySlug = pathParts[2];
|
||||
const cleanSlug = gallerySlug.split('?')[0];
|
||||
token = localStorage.getItem(`gallery_token_${cleanSlug}`);
|
||||
}
|
||||
} else {
|
||||
// It's a slug - use it directly
|
||||
token = localStorage.getItem(`gallery_token_${cleanIdOrSlug}`);
|
||||
}
|
||||
|
||||
if (token) {
|
||||
if (!config.headers) {
|
||||
config.headers = {};
|
||||
}
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
} else {
|
||||
// Fallback to getting slug from the current page URL
|
||||
const pathParts = window.location.pathname.split('/');
|
||||
if (pathParts[1] === 'gallery' && pathParts[2]) {
|
||||
const gallerySlug = pathParts[2];
|
||||
// Remove any query parameters from the slug
|
||||
const cleanSlug = gallerySlug.split('?')[0];
|
||||
const token = localStorage.getItem(`gallery_token_${cleanSlug}`);
|
||||
if (token) {
|
||||
if (!config.headers) {
|
||||
config.headers = {};
|
||||
}
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't set Content-Type for FormData - let browser set it with boundary
|
||||
if (config.data instanceof FormData) {
|
||||
delete config.headers?.['Content-Type'];
|
||||
}
|
||||
@@ -110,10 +37,9 @@ api.interceptors.response.use(
|
||||
// Handle maintenance mode (503)
|
||||
if (error.response?.status === 503) {
|
||||
const isAdminRoute = error.config?.url?.includes('/admin');
|
||||
const hasAdminAuth = error.config?.headers?.Authorization?.startsWith('Bearer ');
|
||||
|
||||
// Only trigger maintenance mode for non-admin routes or unauthenticated admin routes
|
||||
if (!isAdminRoute || !hasAdminAuth) {
|
||||
if (!isAdminRoute) {
|
||||
if (maintenanceModeCallback) {
|
||||
maintenanceModeCallback(true);
|
||||
}
|
||||
@@ -126,8 +52,6 @@ api.interceptors.response.use(
|
||||
const currentPath = window.location.pathname;
|
||||
|
||||
if (isAdminRoute) {
|
||||
// Clear admin token on unauthorized
|
||||
Cookies.remove(ADMIN_TOKEN_KEY);
|
||||
// Only redirect if we're not already on the admin login page
|
||||
if (!currentPath.includes('/admin/login')) {
|
||||
window.location.href = '/admin/login';
|
||||
@@ -144,8 +68,7 @@ api.interceptors.response.use(
|
||||
// Don't clear tokens for image requests - they might just need a retry
|
||||
if (!isImageRequest && galleryMatch && galleryMatch[1]) {
|
||||
const gallerySlug = galleryMatch[1];
|
||||
localStorage.removeItem(`gallery_token_${gallerySlug}`);
|
||||
localStorage.removeItem(`gallery_event_${gallerySlug}`);
|
||||
sessionStorage.removeItem(`gallery_event_${gallerySlug}`);
|
||||
}
|
||||
// Don't redirect - let the component handle the auth state
|
||||
} else if (galleryMatch) {
|
||||
@@ -159,21 +82,3 @@ api.interceptors.response.use(
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// Helper to set auth tokens
|
||||
export const setAuthToken = (token: string, isAdmin: boolean = false) => {
|
||||
const key = isAdmin ? ADMIN_TOKEN_KEY : GALLERY_TOKEN_KEY;
|
||||
Cookies.set(key, token, { expires: 1 }); // 1 day expiry
|
||||
};
|
||||
|
||||
// Helper to clear auth tokens
|
||||
export const clearAuthToken = (isAdmin: boolean = false) => {
|
||||
const key = isAdmin ? ADMIN_TOKEN_KEY : GALLERY_TOKEN_KEY;
|
||||
Cookies.remove(key);
|
||||
};
|
||||
|
||||
// Helper to get auth tokens
|
||||
export const getAuthToken = (isAdmin: boolean = false) => {
|
||||
const key = isAdmin ? ADMIN_TOKEN_KEY : GALLERY_TOKEN_KEY;
|
||||
return Cookies.get(key);
|
||||
};
|
||||
Reference in New Issue
Block a user