|
import cacheService from './cacheService'; |
|
|
|
class CookieService { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async set(name, value, options = {}) { |
|
|
|
const cacheOptions = { |
|
httpOnly: true, |
|
secure: true, |
|
sameSite: 'Strict', |
|
...options |
|
}; |
|
|
|
|
|
let ttl = 60 * 60 * 1000; |
|
if (options.expires) { |
|
ttl = options.expires.getTime() - Date.now(); |
|
} else if (options.maxAge) { |
|
ttl = options.maxAge * 1000; |
|
} |
|
|
|
await cacheService.set(`cookie_${name}`, { value, options }, ttl); |
|
|
|
|
|
|
|
const cookieData = { |
|
value, |
|
options: { |
|
secure: cacheOptions.secure, |
|
sameSite: cacheOptions.sameSite, |
|
expires: options.expires?.toISOString() || null, |
|
maxAge: options.maxAge || null |
|
} |
|
}; |
|
|
|
try { |
|
localStorage.setItem(`__secure_cookie_${name}`, JSON.stringify(cookieData)); |
|
if (import.meta.env.VITE_NODE_ENV === 'development') { |
|
console.log(`πͺ [Cookie] Set secure cookie: ${name}`); |
|
} |
|
} catch (error) { |
|
console.warn(`πͺ [Cookie] Could not set localStorage cookie: ${name}`, error); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
async get(name) { |
|
|
|
const cached = await cacheService.get(`cookie_${name}`); |
|
if (cached) { |
|
return cached.value; |
|
} |
|
|
|
|
|
try { |
|
const cookieData = localStorage.getItem(`__secure_cookie_${name}`); |
|
if (cookieData) { |
|
const parsed = JSON.parse(cookieData); |
|
|
|
if (parsed.options.expires) { |
|
const expiry = new Date(parsed.options.expires); |
|
if (Date.now() > expiry.getTime()) { |
|
await this.remove(name); |
|
return null; |
|
} |
|
} |
|
return parsed.value; |
|
} |
|
} catch (error) { |
|
console.warn(`πͺ [Cookie] Could not read localStorage cookie: ${name}`, error); |
|
} |
|
|
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
async remove(name) { |
|
|
|
await cacheService.remove(`cookie_${name}`); |
|
|
|
|
|
try { |
|
localStorage.removeItem(`__secure_cookie_${name}`); |
|
if (import.meta.env.VITE_NODE_ENV === 'development') { |
|
console.log(`πͺ [Cookie] Removed cookie: ${name}`); |
|
} |
|
} catch (error) { |
|
console.warn(`πͺ [Cookie] Could not remove localStorage cookie: ${name}`, error); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
async clear() { |
|
|
|
const keys = (await cacheService.storage.keys()) || []; |
|
const cookieKeys = keys.filter(key => key.startsWith('cookie_')); |
|
await Promise.all(cookieKeys.map(key => cacheService.remove(key))); |
|
|
|
|
|
try { |
|
const localStorageKeys = Object.keys(localStorage); |
|
const cookieLocalStorageKeys = localStorageKeys.filter(key => key.startsWith('__secure_cookie_')); |
|
cookieLocalStorageKeys.forEach(key => localStorage.removeItem(key)); |
|
|
|
if (import.meta.env.VITE_NODE_ENV === 'development') { |
|
console.log('πͺ [Cookie] Cleared all cookies'); |
|
} |
|
} catch (error) { |
|
console.warn('πͺ [Cookie] Could not clear all localStorage cookies', error); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
async exists(name) { |
|
return (await this.get(name)) !== null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async setAuthTokens(accessToken, rememberMe = false) { |
|
const now = new Date(); |
|
let accessTokenExpiry; |
|
|
|
if (rememberMe) { |
|
|
|
accessTokenExpiry = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); |
|
} else { |
|
|
|
accessTokenExpiry = new Date(now.getTime() + 60 * 60 * 1000); |
|
} |
|
|
|
|
|
await this.set('access_token', accessToken, { |
|
expires: accessTokenExpiry, |
|
secure: true, |
|
sameSite: 'Strict' |
|
}); |
|
|
|
|
|
await this.set('remember_me', rememberMe.toString(), { |
|
expires: accessTokenExpiry, |
|
secure: true, |
|
sameSite: 'Strict' |
|
}); |
|
|
|
if (import.meta.env.VITE_NODE_ENV === 'development') { |
|
console.log('πͺ [Cookie] Set auth tokens with rememberMe:', rememberMe); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
async getAuthTokens() { |
|
try { |
|
const [accessToken, rememberMe] = await Promise.all([ |
|
this.get('access_token'), |
|
this.get('remember_me') |
|
]); |
|
|
|
if (!accessToken) { |
|
return null; |
|
} |
|
|
|
return { |
|
accessToken, |
|
rememberMe: rememberMe === 'true' |
|
}; |
|
} catch (error) { |
|
console.error('πͺ [Cookie] Error getting auth tokens', error); |
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
async clearAuthTokens() { |
|
await Promise.all([ |
|
this.remove('access_token'), |
|
this.remove('remember_me') |
|
]); |
|
|
|
if (import.meta.env.VITE_NODE_ENV === 'development') { |
|
console.log('πͺ [Cookie] Cleared auth tokens'); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async refreshAuthTokens(newAccessToken, rememberMe = false) { |
|
await this.clearAuthTokens(); |
|
await this.setAuthTokens(newAccessToken, rememberMe); |
|
} |
|
} |
|
|
|
|
|
export default new CookieService(); |