beeta/frontend/src/lib/fingerprint.js
2026-01-05 22:54:27 -05:00

63 lines
1.9 KiB
JavaScript

// Guest-only fingerprinting module
// Only guests are fingerprinted - registered users are NOT fingerprinted for privacy
import { browser } from '$app/environment';
let cachedFingerprint = null;
let fingerprintPromise = null;
export async function getGuestFingerprint() {
if (!browser) return null;
// Return cached fingerprint if available
if (cachedFingerprint) return cachedFingerprint;
// Return existing promise if fingerprint is being generated
if (fingerprintPromise) return fingerprintPromise;
fingerprintPromise = generateFingerprint();
cachedFingerprint = await fingerprintPromise;
fingerprintPromise = null;
return cachedFingerprint;
}
async function generateFingerprint() {
try {
const FingerprintJS = await import('@fingerprintjs/fingerprintjs');
const fp = await FingerprintJS.load();
const result = await fp.get();
return result.visitorId;
} catch (error) {
console.error('Failed to generate fingerprint:', error);
// Fallback: generate a simple fingerprint from available data
return generateFallbackFingerprint();
}
}
function generateFallbackFingerprint() {
// Fallback fingerprint using basic browser data
const data = [
navigator.userAgent,
navigator.language,
screen.width + 'x' + screen.height,
screen.colorDepth,
new Date().getTimezoneOffset(),
navigator.hardwareConcurrency || 0,
navigator.deviceMemory || 0
].join('|');
// Simple hash function
let hash = 0;
for (let i = 0; i < data.length; i++) {
const char = data.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return 'fallback_' + Math.abs(hash).toString(36);
}
// Clear cached fingerprint (useful for testing)
export function clearCachedFingerprint() {
cachedFingerprint = null;
fingerprintPromise = null;
}