73 lines
2.9 KiB
TypeScript
73 lines
2.9 KiB
TypeScript
/**
|
|
* Analytics-Utilities für Page-View-Tracking
|
|
* Verwendbar in Middleware und API Routes (keine Next.js-Abhängigkeiten)
|
|
*/
|
|
|
|
// ──── Bot-Filter ────────────────────────────────────────────────────────────
|
|
// Regex für Crawler/Bots (nicht tracken)
|
|
const BOT_PATTERNS =
|
|
/bot|crawl|spider|slurp|mediapartners|adsbot|facebookexternalhit|twitterbot|linkedinbot|whatsapp|telegram|pinterest|slack|discordbot|applebot|bingpreview|google-read-aloud|ia_archiver|mj12bot|ahrefs|semrush|dotbot|rogerbot|screaming\.?frog/i;
|
|
|
|
export function isBot(ua: string): boolean {
|
|
return BOT_PATTERNS.test(ua);
|
|
}
|
|
|
|
// ──── IP-Anonymisierung ────────────────────────────────────────────────────
|
|
// DSGVO: Keine Rückverfolgung einzelner Personen
|
|
// IPv4: letztes Oktett auf 0 (192.168.1.123 → "192.168.1.0")
|
|
// IPv6: Auf /48 kürzen
|
|
export function anonymizeIp(ip: string): string {
|
|
// IPv4-mapped IPv6 (::ffff:1.2.3.4)
|
|
const mapped = ip.match(/^::ffff:(\d+\.\d+\.\d+)\.\d+$/i);
|
|
if (mapped) return `${mapped[1]}.0`;
|
|
|
|
// IPv4
|
|
const v4 = ip.match(/^(\d+\.\d+\.\d+)\.\d+$/);
|
|
if (v4) return `${v4[1]}.0`;
|
|
|
|
// IPv6: erste 3 Gruppen behalten, Rest nullen
|
|
const v6parts = ip.split(":");
|
|
if (v6parts.length >= 3) return `${v6parts.slice(0, 3).join(":")}::`;
|
|
|
|
return "0.0.0.0";
|
|
}
|
|
|
|
// ──── User-Agent-Parsing ────────────────────────────────────────────────────
|
|
export type DeviceType = "mobile" | "tablet" | "desktop";
|
|
export type BrowserName = "Chrome" | "Firefox" | "Safari" | "Edge" | "Opera" | "Other";
|
|
export type OsName = "Windows" | "macOS" | "iOS" | "Android" | "Linux" | "Other";
|
|
|
|
/**
|
|
* Erkennt ob der User ein Mobile-, Tablet- oder Desktop-Gerät nutzt
|
|
*/
|
|
export function parseDevice(ua: string): DeviceType {
|
|
if (/tablet|ipad|playbook|silk/i.test(ua)) return "tablet";
|
|
if (/mobile|android.*mobile|iphone|ipod|blackberry|windows phone/i.test(ua)) return "mobile";
|
|
return "desktop";
|
|
}
|
|
|
|
/**
|
|
* Erkennt den Browser
|
|
* Reihenfolge wichtig: Edge vor Chrome (Edge enthält auch "Chrome/" im UA)
|
|
*/
|
|
export function parseBrowser(ua: string): BrowserName {
|
|
if (/edg\//i.test(ua)) return "Edge";
|
|
if (/opr\//i.test(ua)) return "Opera";
|
|
if (/firefox\//i.test(ua)) return "Firefox";
|
|
if (/chrome\//i.test(ua)) return "Chrome";
|
|
if (/safari\//i.test(ua)) return "Safari";
|
|
return "Other";
|
|
}
|
|
|
|
/**
|
|
* Erkennt das Betriebssystem
|
|
*/
|
|
export function parseOs(ua: string): OsName {
|
|
if (/windows/i.test(ua)) return "Windows";
|
|
if (/iphone|ipad|ipod/i.test(ua)) return "iOS";
|
|
if (/android/i.test(ua)) return "Android";
|
|
if (/mac os x|macintosh/i.test(ua)) return "macOS";
|
|
if (/linux/i.test(ua)) return "Linux";
|
|
return "Other";
|
|
}
|