155 lines
4.0 KiB
JavaScript
155 lines
4.0 KiB
JavaScript
import FingerprintJS from '@fingerprintjs/fingerprintjs';
|
|
|
|
let fpPromise = null;
|
|
let cachedFingerprint = null;
|
|
let cachedDeviceInfo = null;
|
|
|
|
/**
|
|
* Inicializa FingerprintJS (solo una vez)
|
|
*/
|
|
function initFingerprintJS() {
|
|
if (!fpPromise) {
|
|
fpPromise = FingerprintJS.load();
|
|
}
|
|
return fpPromise;
|
|
}
|
|
|
|
/**
|
|
* Obtiene el fingerprint del dispositivo
|
|
* @returns {Promise<{fingerprint: string, deviceInfo: Object}>}
|
|
*/
|
|
export async function getDeviceFingerprint() {
|
|
// Si ya tenemos el fingerprint en caché, devolverlo
|
|
if (cachedFingerprint && cachedDeviceInfo) {
|
|
return {
|
|
fingerprint: cachedFingerprint,
|
|
deviceInfo: cachedDeviceInfo,
|
|
};
|
|
}
|
|
|
|
try {
|
|
const fp = await initFingerprintJS();
|
|
const result = await fp.get();
|
|
|
|
// Extraer información del dispositivo desde los componentes
|
|
const deviceInfo = extractDeviceInfo(result.components);
|
|
|
|
cachedFingerprint = result.visitorId;
|
|
cachedDeviceInfo = deviceInfo;
|
|
|
|
return {
|
|
fingerprint: result.visitorId,
|
|
deviceInfo: deviceInfo,
|
|
};
|
|
} catch (error) {
|
|
console.error('Error obteniendo fingerprint:', error);
|
|
// Fallback: generar un fingerprint básico
|
|
return {
|
|
fingerprint: generateFallbackFingerprint(),
|
|
deviceInfo: {
|
|
browser: navigator.userAgent.includes('Chrome') ? 'Chrome' :
|
|
navigator.userAgent.includes('Firefox') ? 'Firefox' :
|
|
navigator.userAgent.includes('Safari') ? 'Safari' : 'Unknown',
|
|
os: navigator.platform,
|
|
device: 'Unknown',
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extrae información legible del dispositivo desde los componentes de FingerprintJS
|
|
* @param {Object} components - Componentes de FingerprintJS
|
|
* @returns {Object} Información del dispositivo
|
|
*/
|
|
function extractDeviceInfo(components) {
|
|
const info = {
|
|
browser: 'Unknown',
|
|
browserVersion: '',
|
|
os: 'Unknown',
|
|
osVersion: '',
|
|
device: 'Unknown',
|
|
screenResolution: '',
|
|
timezone: '',
|
|
language: navigator.language || '',
|
|
};
|
|
|
|
// Información del navegador
|
|
if (components.browserName) {
|
|
info.browser = components.browserName.value || 'Unknown';
|
|
}
|
|
if (components.browserVersion) {
|
|
info.browserVersion = components.browserVersion.value || '';
|
|
}
|
|
|
|
// Información del sistema operativo
|
|
if (components.os) {
|
|
info.os = components.os.value || 'Unknown';
|
|
}
|
|
if (components.osVersion) {
|
|
info.osVersion = components.osVersion.value || '';
|
|
}
|
|
|
|
// Información del dispositivo
|
|
if (components.deviceMemory) {
|
|
info.device = components.deviceMemory.value ? 'Desktop' : 'Mobile';
|
|
}
|
|
if (components.platform) {
|
|
const platform = components.platform.value?.toLowerCase() || '';
|
|
if (platform.includes('mobile') || platform.includes('android') || platform.includes('iphone')) {
|
|
info.device = 'Mobile';
|
|
} else if (platform.includes('tablet') || platform.includes('ipad')) {
|
|
info.device = 'Tablet';
|
|
} else {
|
|
info.device = 'Desktop';
|
|
}
|
|
}
|
|
|
|
// Resolución de pantalla
|
|
if (components.screenResolution) {
|
|
const res = components.screenResolution.value;
|
|
if (res && res.length >= 2) {
|
|
info.screenResolution = `${res[0]}x${res[1]}`;
|
|
}
|
|
}
|
|
|
|
// Zona horaria
|
|
if (components.timezone) {
|
|
info.timezone = components.timezone.value || '';
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
/**
|
|
* Genera un fingerprint básico como fallback
|
|
* @returns {string} Hash del fingerprint
|
|
*/
|
|
function generateFallbackFingerprint() {
|
|
const data = [
|
|
navigator.userAgent,
|
|
navigator.language,
|
|
navigator.platform,
|
|
screen.width + 'x' + screen.height,
|
|
new Date().getTimezoneOffset(),
|
|
].join('|');
|
|
|
|
// Simple hash (no usar en producción, solo como fallback)
|
|
let hash = 0;
|
|
for (let i = 0; i < data.length; i++) {
|
|
const char = data.charCodeAt(i);
|
|
hash = ((hash << 5) - hash) + char;
|
|
hash = hash & hash; // Convert to 32bit integer
|
|
}
|
|
return Math.abs(hash).toString(36);
|
|
}
|
|
|
|
/**
|
|
* Limpia el caché del fingerprint (útil para testing)
|
|
*/
|
|
export function clearFingerprintCache() {
|
|
cachedFingerprint = null;
|
|
cachedDeviceInfo = null;
|
|
}
|
|
|