trello_fake/lib/authService.ts

252 lines
5.6 KiB
TypeScript

/**
* Servicio de autenticación para Dolibarr
*
* Maneja login, logout y gestión de tokens/sesiones
*/
// Tipos para la autenticación
export interface AuthUser {
id: number;
login: string;
firstname: string;
lastname: string;
email: string;
admin: boolean;
}
export interface LoginCredentials {
login: string;
password: string;
}
export interface LoginResponse {
success: boolean;
token?: string;
user?: AuthUser;
error?: string;
}
export interface AuthState {
isAuthenticated: boolean;
user: AuthUser | null;
token: string | null;
}
// Constantes
const AUTH_TOKEN_KEY = "dolibarr_auth_token";
const AUTH_USER_KEY = "dolibarr_auth_user";
/**
* Obtiene la URL base de la API de Dolibarr
*/
function getApiUrl(): string {
// En cliente, usar proxy para evitar problemas de red/CORS
if (typeof window !== "undefined") {
return "/api/dolibarr";
}
const url = process.env.DOLIBARR_API_URL || process.env.NEXT_PUBLIC_API_URL;
if (!url) {
throw new Error("API URL not configured");
}
return url;
}
/**
* Realiza login contra la API de Dolibarr
* Dolibarr usa el endpoint /login para autenticar y devuelve un token
*/
export async function login(credentials: LoginCredentials): Promise<LoginResponse> {
try {
const apiUrl = getApiUrl();
// Dolibarr API login endpoint
const response = await fetch(`${apiUrl}/login`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
},
body: JSON.stringify({
login: credentials.login,
password: credentials.password,
}),
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
if (response.status === 401 || response.status === 403) {
return {
success: false,
error: "Credenciales incorrectas. Verifica tu usuario y contraseña.",
};
}
return {
success: false,
error: errorData.error || `Error del servidor: ${response.status}`,
};
}
const data = await response.json();
// Dolibarr devuelve el token directamente en success.token
const token = data.success?.token || data.token;
if (!token) {
return {
success: false,
error: "No se recibió token de autenticación",
};
}
// Obtener información del usuario con el token
const userResponse = await fetch(`${apiUrl}/users/info?DOLAPIKEY=${token}`, {
headers: {
"Accept": "application/json",
},
});
let user: AuthUser | undefined;
if (userResponse.ok) {
const userData = await userResponse.json();
user = {
id: parseInt(userData.id),
login: userData.login,
firstname: userData.firstname || "",
lastname: userData.lastname || "",
email: userData.email || "",
admin: userData.admin === "1" || userData.admin === 1,
};
}
// Guardar en localStorage
saveAuthData(token, user);
return {
success: true,
token,
user,
};
} catch (error) {
console.error("Login error:", error);
return {
success: false,
error: "Error de conexión. Verifica tu conexión a internet.",
};
}
}
/**
* Realiza logout - limpia datos locales
* Nota: Dolibarr no tiene endpoint de logout, los tokens expiran solos
*/
export async function logout(): Promise<void> {
// Limpiar datos de autenticación
clearAuthData();
}
/**
* Guarda los datos de autenticación en localStorage y cookie
*/
function saveAuthData(token: string, user?: AuthUser): void {
if (typeof window === "undefined") return;
localStorage.setItem(AUTH_TOKEN_KEY, token);
if (user) {
localStorage.setItem(AUTH_USER_KEY, JSON.stringify(user));
}
// También guardar en cookie para que el middleware pueda leerlo
// Cookie de sesión: se elimina al cerrar el navegador
document.cookie = `${AUTH_TOKEN_KEY}=${token}; path=/; SameSite=Lax`;
}
/**
* Limpia los datos de autenticación
*/
function clearAuthData(): void {
if (typeof window === "undefined") return;
localStorage.removeItem(AUTH_TOKEN_KEY);
localStorage.removeItem(AUTH_USER_KEY);
// Limpiar cookie
document.cookie = `${AUTH_TOKEN_KEY}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
}
/**
* Obtiene el token guardado
*/
export function getStoredToken(): string | null {
if (typeof window === "undefined") return null;
return localStorage.getItem(AUTH_TOKEN_KEY);
}
/**
* Obtiene el usuario guardado
*/
export function getStoredUser(): AuthUser | null {
if (typeof window === "undefined") return null;
const userJson = localStorage.getItem(AUTH_USER_KEY);
if (!userJson) return null;
try {
return JSON.parse(userJson);
} catch {
return null;
}
}
/**
* Verifica si el token actual es válido
*/
export async function verifyToken(): Promise<boolean> {
const token = getStoredToken();
if (!token) {
return false;
}
try {
const apiUrl = getApiUrl();
// Verificar token haciendo una llamada simple a la API
const response = await fetch(`${apiUrl}/users/info?DOLAPIKEY=${token}`, {
headers: {
"Accept": "application/json",
},
});
if (!response.ok) {
// Token inválido o expirado
clearAuthData();
return false;
}
return true;
} catch {
return false;
}
}
/**
* Obtiene el estado de autenticación actual
*/
export function getAuthState(): AuthState {
const token = getStoredToken();
const user = getStoredUser();
return {
isAuthenticated: !!token,
user,
token,
};
}