mediahub-fe/lib/auth-utils.ts

241 lines
7.6 KiB
TypeScript

import Cookies from "js-cookie";
import { toast } from "sonner";
import {
AuthCookies,
ProfileData,
LoginFormData,
NavigationConfig
} from "@/types/auth";
import { getCookiesDecrypt, setCookiesEncrypt } from "@/lib/utils";
// Navigation configuration based on user roles
export const NAVIGATION_CONFIG: NavigationConfig[] = [
{ roleId: 18, path: "/in/dashboard/executive-data", label: "Executive Data Dashboard" },
{ roleId: 2, path: "/in/dashboard/executive", label: "Executive Dashboard" },
{ roleId: 3, path: "/in/dashboard", label: "Dashboard" },
{ roleId: 4, path: "/in/dashboard", label: "Dashboard" },
{ roleId: 9, path: "/in/dashboard", label: "Dashboard" },
{ roleId: 10, path: "/in/dashboard", label: "Dashboard" },
{ roleId: 11, path: "/in/dashboard", label: "Dashboard" },
{ roleId: 12, path: "/in/dashboard", label: "Dashboard" },
{ roleId: 19, path: "/in/dashboard", label: "Dashboard" },
];
// Cookie management utilities
export const setAuthCookies = (accessToken: string, refreshToken: string): void => {
const dateTime = new Date();
const newTime = dateTime.getTime() + 10 * 60 * 1000; // 10 minutes
Cookies.set("access_token", accessToken, { expires: 1 });
Cookies.set("refresh_token", refreshToken, { expires: 1 });
Cookies.set("time_refresh", new Date(newTime).toISOString(), { expires: 1 });
Cookies.set("is_first_login", String(true), { secure: true, sameSite: "strict" });
};
export const setProfileCookies = (profile: ProfileData): void => {
Cookies.set("home_path", profile.homePath || "", { expires: 1 });
Cookies.set("profile_picture", profile.profilePictureUrl || "", { expires: 1 });
Cookies.set("state", profile.userLevel?.name || "", { expires: 1 });
Cookies.set("state-prov", profile.userLevel?.province?.provName || "", { expires: 1 });
setCookiesEncrypt("uie", profile.id, { expires: 1 });
setCookiesEncrypt("urie", profile.roleId.toString(), { expires: 1 });
setCookiesEncrypt("urne", profile.role?.name || "", { expires: 1 });
setCookiesEncrypt("ulie", profile.userLevel?.id.toString() || "", { expires: 1 });
setCookiesEncrypt("uplie", profile.userLevel?.parentLevelId?.toString() || "", { expires: 1 });
setCookiesEncrypt("ulne", profile.userLevel?.levelNumber.toString() || "", { expires: 1 });
setCookiesEncrypt("ufne", profile.fullname, { expires: 1 });
setCookiesEncrypt("ulnae", profile.userLevel?.name || "", { expires: 1 });
setCookiesEncrypt("uinse", profile.instituteId || "", { expires: 1 });
Cookies.set("status", "login", { expires: 1 });
};
export const clearAllCookies = (): void => {
Object.keys(Cookies.get()).forEach((cookieName) => {
Cookies.remove(cookieName);
});
};
export const getAuthCookies = (): Partial<AuthCookies> => {
return {
access_token: Cookies.get("access_token"),
refresh_token: Cookies.get("refresh_token"),
time_refresh: Cookies.get("time_refresh"),
is_first_login: Cookies.get("is_first_login"),
home_path: Cookies.get("home_path"),
profile_picture: Cookies.get("profile_picture"),
state: Cookies.get("state"),
"state-prov": Cookies.get("state-prov"),
uie: getCookiesDecrypt("uie"),
urie: getCookiesDecrypt("urie"),
urne: getCookiesDecrypt("urne"),
ulie: getCookiesDecrypt("ulie"),
uplie: getCookiesDecrypt("uplie"),
ulne: getCookiesDecrypt("ulne"),
ufne: getCookiesDecrypt("ufne"),
ulnae: getCookiesDecrypt("ulnae"),
uinse: getCookiesDecrypt("uinse"),
status: Cookies.get("status"),
};
};
// User validation utilities
export const isUserEligible = (profile: ProfileData): boolean => {
return !(
profile.isInternational ||
!profile.isActive ||
profile.isDelete
);
};
export const isProtectedRole = (roleId: number): boolean => {
const protectedRoles = [2, 3, 4, 9, 10, 11, 12, 18, 19];
return protectedRoles.includes(roleId);
};
export const isSpecialLevel = (userLevelId: number, parentLevelId?: number): boolean => {
return userLevelId === 794 || parentLevelId === 761;
};
// Navigation utilities
export const getNavigationPath = (roleId: number, userLevelId?: number, parentLevelId?: number): string => {
const config = NAVIGATION_CONFIG.find(nav => nav.roleId === roleId);
if (config) {
// Special handling for role 2 with specific level conditions
if (roleId === 2 && userLevelId && parentLevelId && isSpecialLevel(userLevelId, parentLevelId)) {
return "/in/dashboard";
}
return config.path;
}
return "/"; // Default fallback
};
// Error handling utilities
export const handleAuthError = (error: any, defaultMessage: string = "Authentication failed"): string => {
if (typeof error === "string") {
return error;
}
if (error?.message) {
return error.message;
}
if (error?.response?.data?.message) {
return error.response.data.message;
}
return defaultMessage;
};
export const showAuthError = (error: any, defaultMessage: string = "Authentication failed"): void => {
const message = handleAuthError(error, defaultMessage);
toast.error(message);
};
export const showAuthSuccess = (message: string): void => {
toast.success(message);
};
// Form validation utilities
export const validateEmail = (email: string): boolean => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
export const validatePassword = (password: string): { isValid: boolean; errors: string[] } => {
const errors: string[] = [];
if (password.length < 6) {
errors.push("Password must be at least 6 characters long");
}
if (password.length > 100) {
errors.push("Password must be less than 100 characters");
}
return {
isValid: errors.length === 0,
errors
};
};
// Loading state utilities
export const createLoadingState = () => {
let isLoading = false;
return {
get: () => isLoading,
set: (loading: boolean) => { isLoading = loading; },
withLoading: async <T>(fn: () => Promise<T>): Promise<T> => {
isLoading = true;
try {
return await fn();
} finally {
isLoading = false;
}
}
};
};
// Constants
export const AUTH_CONSTANTS = {
CLIENT_ID: "mediahub-app",
GRANT_TYPE: "password",
TOKEN_REFRESH_INTERVAL: 10 * 60 * 1000, // 10 minutes
MAX_LOGIN_ATTEMPTS: 3,
LOCKOUT_DURATION: 15 * 60 * 1000, // 15 minutes
} as const;
// Rate limiting utilities
export class LoginRateLimiter {
private attempts: Map<string, { count: number; lastAttempt: number }> = new Map();
canAttempt(username: string): boolean {
const userAttempts = this.attempts.get(username);
if (!userAttempts) {
return true;
}
const timeSinceLastAttempt = Date.now() - userAttempts.lastAttempt;
if (timeSinceLastAttempt > AUTH_CONSTANTS.LOCKOUT_DURATION) {
this.attempts.delete(username);
return true;
}
return userAttempts.count < AUTH_CONSTANTS.MAX_LOGIN_ATTEMPTS;
}
recordAttempt(username: string): void {
const userAttempts = this.attempts.get(username);
if (userAttempts) {
userAttempts.count++;
userAttempts.lastAttempt = Date.now();
} else {
this.attempts.set(username, { count: 1, lastAttempt: Date.now() });
}
}
resetAttempts(username: string): void {
this.attempts.delete(username);
}
getRemainingTime(username: string): number {
const userAttempts = this.attempts.get(username);
if (!userAttempts) {
return 0;
}
const timeSinceLastAttempt = Date.now() - userAttempts.lastAttempt;
return Math.max(0, AUTH_CONSTANTS.LOCKOUT_DURATION - timeSinceLastAttempt);
}
}
// Global rate limiter instance
export const loginRateLimiter = new LoginRateLimiter();