- Enable TypeScript noUncheckedIndexedAccess and fix 133 resulting errors across 46 files with proper null guards, optional chaining, and fallbacks - Extract education/gamification ghost feature MSW handlers into handlers-ghost.ts - Add Storybook test plugin documentation in vitest.config.ts - Document abandoned go-clamd dependency (2017) as tech debt in upload_validator.go Co-authored-by: Cursor <cursoragent@cursor.com>
112 lines
2.8 KiB
TypeScript
112 lines
2.8 KiB
TypeScript
/**
|
|
* CookieService - Service de gestion des cookies côté client
|
|
* SECURITY: Pour les cookies httpOnly, le backend les gère directement
|
|
* Ce service gère uniquement les cookies non-httpOnly si nécessaire
|
|
*/
|
|
|
|
/**
|
|
* Définit un cookie
|
|
* Note: Pour les cookies httpOnly, le backend doit les setter via Set-Cookie header
|
|
* @param name - Nom du cookie
|
|
* @param value - Valeur du cookie
|
|
* @param days - Nombre de jours avant expiration
|
|
* @param options - Options supplémentaires (path, domain, secure, sameSite)
|
|
*/
|
|
export function setCookie(
|
|
name: string,
|
|
value: string,
|
|
days?: number,
|
|
options?: {
|
|
path?: string;
|
|
domain?: string;
|
|
secure?: boolean;
|
|
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
},
|
|
): void {
|
|
let cookieString = `${name}=${encodeURIComponent(value)}`;
|
|
|
|
if (days !== undefined) {
|
|
const date = new Date();
|
|
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
|
cookieString += `; expires=${date.toUTCString()}`;
|
|
}
|
|
|
|
if (options?.path) {
|
|
cookieString += `; path=${options.path}`;
|
|
}
|
|
|
|
if (options?.domain) {
|
|
cookieString += `; domain=${options.domain}`;
|
|
}
|
|
|
|
if (options?.secure || import.meta.env.PROD) {
|
|
cookieString += '; secure';
|
|
}
|
|
|
|
if (options?.sameSite) {
|
|
cookieString += `; sameSite=${options.sameSite}`;
|
|
}
|
|
|
|
document.cookie = cookieString;
|
|
}
|
|
|
|
/**
|
|
* Récupère un cookie par son nom
|
|
* Note: Les cookies httpOnly ne sont pas accessibles via JavaScript
|
|
* @param name - Nom du cookie
|
|
* @returns Valeur du cookie ou null si non trouvé
|
|
*/
|
|
export function getCookie(name: string): string | null {
|
|
const nameEQ = `${name}=`;
|
|
const cookies = document.cookie.split(';');
|
|
|
|
for (let i = 0; i < cookies.length; i++) {
|
|
let cookie = cookies[i];
|
|
if (cookie == null) continue;
|
|
while (cookie.charAt(0) === ' ') {
|
|
cookie = cookie.substring(1, cookie.length);
|
|
}
|
|
if (cookie.indexOf(nameEQ) === 0) {
|
|
return decodeURIComponent(cookie.substring(nameEQ.length, cookie.length));
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Supprime un cookie
|
|
* @param name - Nom du cookie
|
|
* @param options - Options (path, domain)
|
|
*/
|
|
export function deleteCookie(
|
|
name: string,
|
|
options?: { path?: string; domain?: string },
|
|
): void {
|
|
let cookieString = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC`;
|
|
|
|
if (options?.path) {
|
|
cookieString += `; path=${options.path}`;
|
|
}
|
|
|
|
if (options?.domain) {
|
|
cookieString += `; domain=${options.domain}`;
|
|
}
|
|
|
|
document.cookie = cookieString;
|
|
}
|
|
|
|
/**
|
|
* Vérifie si les cookies sont supportés
|
|
* @returns true si les cookies sont supportés
|
|
*/
|
|
export function areCookiesSupported(): boolean {
|
|
try {
|
|
document.cookie = 'test=1';
|
|
const supported = document.cookie.indexOf('test=') !== -1;
|
|
document.cookie = 'test=; expires=Thu, 01 Jan 1970 00:00:00 UTC';
|
|
return supported;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|