import jwt_decode from "jwt-decode"; import CookieService from "../CookieService/CookieService"; import UserStore from "@Front/Stores/CustomerStore"; import CustomerStore from "@Front/Stores/CustomerStore"; import { FrontendVariables } from "@Front/Config/VariablesFront"; enum PROVIDER_OPENID { idNot = "idNot", } export interface IUserJwtPayload { userId: string; email: string | null; openId: { providerName: PROVIDER_OPENID; userId: string | number; }; office_Id: string; role: string; rules: string[]; exp: number; } export interface ICustomerJwtPayload { customerId: string; email: string; exp: number; } export default class JwtService { private static instance: JwtService; private constructor() {} public static getInstance() { return (this.instance ??= new this()); } public getUserJwtPayload(): IUserJwtPayload | undefined { const accessToken = CookieService.getInstance().getCookie("leCoffreAccessToken"); if (!accessToken) return; return jwt_decode(accessToken); } public getCustomerJwtPayload(): ICustomerJwtPayload | undefined { const accessToken = CookieService.getInstance().getCookie("leCoffreAccessToken"); if (!accessToken) return; return jwt_decode(accessToken); } public decodeJwt(): IUserJwtPayload | undefined { const accessToken = CookieService.getInstance().getCookie("leCoffreAccessToken"); if (!accessToken) return; return jwt_decode(accessToken); } public decodeCustomerJwt(): ICustomerJwtPayload | undefined { const accessToken = CookieService.getInstance().getCookie("leCoffreAccessToken"); if (!accessToken) return; return jwt_decode(accessToken); } /** * @description : set a cookie with a name and a value that expire in 7 days * @throws {Error} If the name or the value is empty */ public async refreshToken(refreshToken: string): Promise { const userToken = jwt_decode(refreshToken) as IUserJwtPayload; const customerToken = jwt_decode(refreshToken) as ICustomerJwtPayload; if (userToken?.exp && userToken.exp > Math.floor(Date.now() / 1000)) { const variables = FrontendVariables.getInstance(); if (userToken?.userId) { try { const headers = new Headers(); headers.append("Authorization", `Bearer ${refreshToken}`); const response = await fetch( `${ variables.BACK_API_PROTOCOL + variables.BACK_API_HOST + variables.BACK_API_ROOT_URL + variables.BACK_API_VERSION }/idnot/user/auth/refresh-token`, { method: "POST", headers: headers }, ); const newAccessToken: { accessToken: string } = await response.json(); if (newAccessToken) { await UserStore.instance.connect(newAccessToken.accessToken, refreshToken); return true; } } catch (err) { console.error(err); return false; } } else if (customerToken?.customerId) { try { const headers = new Headers(); headers.append("Authorization", `Bearer ${refreshToken}`); const response = await fetch( `${ variables.BACK_API_PROTOCOL + variables.BACK_API_HOST + variables.BACK_API_ROOT_URL + variables.BACK_API_VERSION }/id360/customers/refresh-token`, { method: "POST", headers: headers }, ); const newAccessToken: { accessToken: string } = await response.json(); if (newAccessToken) { await CustomerStore.instance.connect(newAccessToken.accessToken, refreshToken); return true; } } catch (err) { console.error(err); return false; } } } return false; } public async forceRefreshToken(refreshToken: string): Promise { const userToken = jwt_decode(refreshToken) as IUserJwtPayload; const customerToken = jwt_decode(refreshToken) as ICustomerJwtPayload; const variables = FrontendVariables.getInstance(); if (userToken?.userId) { try { const headers = new Headers(); headers.append("Authorization", `Bearer ${refreshToken}`); const response = await fetch( `${ variables.BACK_API_PROTOCOL + variables.BACK_API_HOST + variables.BACK_API_ROOT_URL + variables.BACK_API_VERSION }/idnot/user/auth/refresh-token`, { method: "POST", headers: headers }, ); const newAccessToken: { accessToken: string } = await response.json(); if (newAccessToken) { await UserStore.instance.connect(newAccessToken.accessToken, refreshToken); return true; } } catch (err) { console.error(err); return false; } } else if (customerToken?.customerId) { try { const headers = new Headers(); headers.append("Authorization", `Bearer ${refreshToken}`); const response = await fetch( `${ variables.BACK_API_PROTOCOL + variables.BACK_API_HOST + variables.BACK_API_ROOT_URL + variables.BACK_API_VERSION }/id360/customers/refresh-token`, { method: "POST", headers: headers }, ); const newAccessToken: { accessToken: string } = await response.json(); if (newAccessToken) { await CustomerStore.instance.connect(newAccessToken.accessToken, refreshToken); return true; } } catch (err) { console.error(err); return false; } } return false; } public hasRule(name: string, action: string) { const token = this.decodeJwt(); if (!token) return false; return token?.rules?.some((rule: string) => rule === `${action} ${name}`); } /** * Debug method to log JWT token details including rules */ public debugJwtToken() { const token = this.decodeJwt(); if (!token) { console.warn("No JWT token found"); return null; } console.log("=== JWT Token Debug Info ==="); console.log("User ID:", token.userId); console.log("Email:", token.email); console.log("Role:", token.role); console.log("Office ID:", token.office_Id); console.log("Rules count:", token.rules?.length || 0); console.log("Rules:", token.rules); console.log("Expiration:", new Date(token.exp * 1000).toISOString()); console.log("============================="); return token; } /** * Check if a specific rule exists in the JWT token */ public checkSpecificRule(name: string, action: string) { const token = this.decodeJwt(); if (!token) { console.warn("No JWT token found"); return false; } const expectedRule = `${action} ${name}`; const hasRule = token?.rules?.some((rule: string) => rule === expectedRule); console.log(`=== Rule Check: ${expectedRule} ===`); console.log("Expected rule:", expectedRule); console.log("Available rules:", token.rules); console.log("Rule found:", hasRule); console.log("============================="); return hasRule; } /** * Compare JWT rules with expected rules from database */ public compareRulesWithDatabase(expectedRules: string[]) { const token = this.decodeJwt(); if (!token) { console.warn("No JWT token found"); return { missing: expectedRules, extra: [], matches: [] }; } const jwtRules = token.rules || []; const missing = expectedRules.filter(rule => !jwtRules.includes(rule)); const extra = jwtRules.filter(rule => !expectedRules.includes(rule)); const matches = jwtRules.filter(rule => expectedRules.includes(rule)); console.log("=== Rules Comparison ==="); console.log("Expected rules (from DB):", expectedRules); console.log("JWT rules:", jwtRules); console.log("Missing rules:", missing); console.log("Extra rules:", extra); console.log("Matching rules:", matches); console.log("========================="); return { missing, extra, matches }; } }