240 lines
7.3 KiB
TypeScript
240 lines
7.3 KiB
TypeScript
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<boolean> {
|
|
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<boolean> {
|
|
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 };
|
|
}
|
|
}
|