add landing and subscription plans

Signed-off-by: Omar Sánchez Pizarro <omar.sanchez@pistacero.net>
This commit is contained in:
Omar Sánchez Pizarro
2026-01-20 23:49:19 +01:00
parent 05f0455744
commit 6ec8855c00
79 changed files with 8839 additions and 361 deletions

View File

@@ -0,0 +1,154 @@
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;
}