UNPKG

@sl_1503/browser-fingerprinting

Version:

A browser-based fingerprinting utility to collect and send device/browser info.

208 lines (207 loc) 7.07 kB
function s(e, t = "unsupported") { try { return e(); } catch { return t; } } function c(e) { if (e && typeof e == "object" && !Array.isArray(e)) { const t = {}; return Object.keys(e).sort().forEach((n) => { t[n] = c(e[n]); }), JSON.stringify(t); } else if (Array.isArray(e)) return JSON.stringify(e.map(c)); return JSON.stringify(e); } function l(e) { const t = c(e); let n = 5381; for (let i = 0; i < t.length; i++) n = n * 33 ^ t.charCodeAt(i); return "fp_" + (n >>> 0).toString(16); } function d() { const e = document.createElement("canvas"), t = e.getContext("2d"); return t.textBaseline = "top", t.font = "14px Arial", t.fillStyle = "#f60", t.fillRect(0, 0, 100, 100), t.fillStyle = "#069", t.fillText("custom_fp_test", 10, 10), e.toDataURL(); } function f() { const e = document.createElement("canvas"), t = e.getContext("webgl") || e.getContext("experimental-webgl"); if (!t) return "unsupported"; const n = t.getExtension("WEBGL_debug_renderer_info"), i = n ? t.getParameter(n.UNMASKED_VENDOR_WEBGL) : "unknown", o = n ? t.getParameter(n.UNMASKED_RENDERER_WEBGL) : "unknown"; return `${i}~${o}`; } function g() { try { const e = document.createElement("canvas"), t = e.getContext("webgl") || e.getContext("experimental-webgl"); return t ? t.getSupportedExtensions() : "unsupported"; } catch { return "unsupported"; } } async function p() { try { const e = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(1, 44100, 44100), t = e.createOscillator(), n = e.createDynamicsCompressor(); return t.type = "triangle", t.frequency.setValueAtTime(1e4, e.currentTime), n.threshold.setValueAtTime(-50, e.currentTime), n.knee.setValueAtTime(40, e.currentTime), n.ratio.setValueAtTime(12, e.currentTime), n.attack.setValueAtTime(0, e.currentTime), n.release.setValueAtTime(0.25, e.currentTime), t.connect(n), n.connect(e.destination), t.start(0), e.startRendering(), new Promise((i) => { e.oncomplete = (o) => { const r = o.renderedBuffer.getChannelData(0).slice(0, 30).join(","); i(r); }; }); } catch { return "unsupported"; } } function m() { const e = ["monospace", "sans-serif", "serif"], t = ["Arial", "Courier New", "Georgia", "Times New Roman", "Verdana"], n = [], i = document.createElement("span"); return i.style.position = "absolute", i.style.left = "-9999px", i.style.fontSize = "72px", i.textContent = "mmmmmmmmmmlli", document.body.appendChild(i), e.forEach((o) => { i.style.fontFamily = o; const r = i.offsetWidth; t.forEach((a) => { i.style.fontFamily = `${a},${o}`, i.offsetWidth !== r && !n.includes(a) && n.push(a); }); }), document.body.removeChild(i), n; } function h() { return navigator.plugins ? Array.from(navigator.plugins).map((e) => e.name) : "unsupported"; } function v() { return { webdriver: navigator.webdriver || !1, isHeadless: /HeadlessChrome/.test(navigator.userAgent), pluginsEmpty: navigator.plugins.length === 0, screenTooPerfect: window.outerWidth === 800 && window.outerHeight === 600 }; } function w() { var e; return ((e = screen.orientation) == null ? void 0 : e.type) || window.orientation || "unknown"; } async function y() { return new Promise((e) => { const t = new RTCPeerConnection({ iceServers: [] }); t.createDataChannel(""), t.createOffer().then((n) => t.setLocalDescription(n)), t.onicecandidate = (n) => { if (!n || !n.candidate) return; const i = n.candidate.candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3})/); i && e(i[1]), t.close(); }, setTimeout(() => e("unavailable"), 1e3); }); } async function b() { try { return (await (await fetch("https://api.ipify.org?format=json")).json()).ip; } catch { return "unavailable"; } } async function T() { var e; if (!((e = navigator.mediaDevices) != null && e.enumerateDevices)) return "unsupported"; try { return (await navigator.mediaDevices.enumerateDevices()).map((n) => `${n.kind}:${n.label || "hidden"}`); } catch { return "unavailable"; } } function C() { return "ontouchstart" in window || navigator.maxTouchPoints > 0; } function x() { const e = navigator.connection || navigator.mozConnection || navigator.webkitConnection; return e ? { type: e.type, effectiveType: e.effectiveType, downlink: e.downlink, rtt: e.rtt } : "unsupported"; } function A() { return new Promise((e) => { let t = speechSynthesis.getVoices(); if (t.length) return e(t.map((n) => n.name)); speechSynthesis.onvoiceschanged = () => e(speechSynthesis.getVoices().map((n) => n.name)); }); } function P() { return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; } function S() { const e = navigator.userAgent, t = /Mobi|Android/i.test(e), i = /Tablet|iPad/i.test(e) ? "tablet" : t ? "mobile" : "desktop"; let o = "Unknown Device"; if (/iPhone/.test(e)) o = "iPhone"; else if (/iPad/.test(e)) o = "iPad"; else if (/Macintosh/.test(e)) o = "Mac"; else if (/Android/.test(e)) { const r = e.match(/Android.*;\s([^)]+)/); o = r ? r[1].trim() : "Android device"; } else /Windows/.test(e) && (o = "Windows PC"); return { deviceType: i, deviceLabel: o }; } async function E() { const [ e, t, n, i, o ] = await Promise.all([ p(), y(), b(), T(), A() ]), r = S(), a = { userAgent: navigator.userAgent, languages: navigator.languages || [], language: navigator.language, platform: navigator.platform, screenResolution: `${screen.width}x${screen.height}`, colorDepth: screen.colorDepth, timezoneOffset: (/* @__PURE__ */ new Date()).getTimezoneOffset(), timeZone: s(() => Intl.DateTimeFormat().resolvedOptions().timeZone), hardwareConcurrency: navigator.hardwareConcurrency || "unknown", deviceMemory: navigator.deviceMemory || "unknown", maxTouchPoints: navigator.maxTouchPoints || 0, touchSupport: C(), devicePixelRatio: window.devicePixelRatio || 1, canvasFingerprint: s(d), webGLFingerprint: s(f), webGLExtensions: s(g), audioFingerprint: e, fonts: s(m), plugins: s(h), orientation: w(), mathFingerprint: [ Math.acos(0.123456789), Math.sin(1), Math.tan(1), Math.exp(1) ].join(","), webRTCLocalIP: t, publicIP: n, mediaDevices: i, automationFlags: v(), networkInfo: x(), speechVoices: o, preferredColorScheme: P(), deviceType: r.deviceType, deviceLabel: r.deviceLabel, deviceCapabilities: { bluetooth: !!navigator.bluetooth, usb: !!navigator.usb }, featureFlags: { localStorage: typeof localStorage < "u", sessionStorage: typeof sessionStorage < "u", indexedDB: !!window.indexedDB, serviceWorker: "serviceWorker" in navigator, webRTC: typeof RTCPeerConnection < "u" } }, u = l(a).slice(0, 13); return { fingerprint: a, shortHash: u }; } export { E as default, E as getFingerprint };