You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
7.0 KiB
197 lines
7.0 KiB
(function () { |
|
'use strict'; |
|
|
|
var cfg = window.__AUDIT_BEACON__; |
|
if (!cfg || !cfg.context) { |
|
return; |
|
} |
|
|
|
function csrfToken() { |
|
var meta = document.querySelector('meta[name="csrf-token"]'); |
|
return meta ? meta.getAttribute('content') : ''; |
|
} |
|
|
|
function postBeacon(url, fields) { |
|
var fd = new FormData(); |
|
fd.append('_token', csrfToken()); |
|
Object.keys(fields).forEach(function (key) { |
|
if (fields[key] !== null && fields[key] !== undefined && fields[key] !== '') { |
|
fd.append(key, fields[key]); |
|
} |
|
}); |
|
|
|
if (navigator.sendBeacon) { |
|
navigator.sendBeacon(url, fd); |
|
return; |
|
} |
|
|
|
fetch(url, { method: 'POST', body: fd, credentials: 'same-origin', keepalive: true }).catch(function () {}); |
|
} |
|
|
|
function detectBrowser() { |
|
var ua = navigator.userAgent; |
|
if (ua.indexOf('Edg/') !== -1) { |
|
return { name: 'Edge', version: (ua.match(/Edg\/([\d.]+)/) || [])[1] || '' }; |
|
} |
|
if (ua.indexOf('OPR/') !== -1 || ua.indexOf('Opera') !== -1) { |
|
return { name: 'Opera', version: (ua.match(/(?:OPR|Opera)\/([\d.]+)/) || [])[1] || '' }; |
|
} |
|
if (ua.indexOf('Chrome/') !== -1 && ua.indexOf('Edg/') === -1) { |
|
return { name: 'Chrome', version: (ua.match(/Chrome\/([\d.]+)/) || [])[1] || '' }; |
|
} |
|
if (ua.indexOf('Firefox/') !== -1) { |
|
return { name: 'Firefox', version: (ua.match(/Firefox\/([\d.]+)/) || [])[1] || '' }; |
|
} |
|
if (ua.indexOf('Safari/') !== -1 && ua.indexOf('Chrome') === -1) { |
|
return { name: 'Safari', version: (ua.match(/Version\/([\d.]+)/) || [])[1] || '' }; |
|
} |
|
return { name: 'Unknown', version: '' }; |
|
} |
|
|
|
function detectOs() { |
|
var ua = navigator.userAgent; |
|
var platform = navigator.platform || ''; |
|
if (/Windows NT 10/.test(ua)) return { name: 'Windows', version: '10/11' }; |
|
if (/Windows NT 6\.3/.test(ua)) return { name: 'Windows', version: '8.1' }; |
|
if (/Windows NT 6\.1/.test(ua)) return { name: 'Windows', version: '7' }; |
|
if (/Android/.test(ua)) return { name: 'Android', version: (ua.match(/Android ([\d.]+)/) || [])[1] || '' }; |
|
if (/iPhone|iPad|iPod/.test(ua)) return { name: 'iOS', version: (ua.match(/OS ([\d_]+)/) || [])[1].replace(/_/g, '.') || '' }; |
|
if (/Mac OS X/.test(ua)) return { name: 'macOS', version: (ua.match(/Mac OS X ([\d_]+)/) || [])[1].replace(/_/g, '.') || '' }; |
|
if (/Linux/.test(ua) || /Linux/.test(platform)) return { name: 'Linux', version: '' }; |
|
return { name: platform || 'Unknown', version: '' }; |
|
} |
|
|
|
function detectGpu() { |
|
try { |
|
var canvas = document.createElement('canvas'); |
|
var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); |
|
if (!gl) return ''; |
|
var ext = gl.getExtension('WEBGL_debug_renderer_info'); |
|
if (!ext) return ''; |
|
var renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL); |
|
return renderer ? String(renderer).substring(0, 255) : ''; |
|
} catch (e) { |
|
return ''; |
|
} |
|
} |
|
|
|
function detectWebrtcIp() { |
|
return new Promise(function (resolve) { |
|
var resolved = false; |
|
var finish = function (ip) { |
|
if (resolved) return; |
|
resolved = true; |
|
resolve(ip || ''); |
|
}; |
|
|
|
setTimeout(function () { finish(''); }, 2500); |
|
|
|
try { |
|
var RTCPeer = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection; |
|
if (!RTCPeer) { |
|
finish(''); |
|
return; |
|
} |
|
var pc = new RTCPeer({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] }); |
|
pc.createDataChannel(''); |
|
pc.createOffer().then(function (offer) { return pc.setLocalDescription(offer); }).catch(function () { finish(''); }); |
|
pc.onicecandidate = function (event) { |
|
if (!event || !event.candidate || !event.candidate.candidate) return; |
|
var parts = event.candidate.candidate.split(' '); |
|
var ip = parts[4]; |
|
if (ip && ip.indexOf('.') !== -1) { |
|
finish(ip); |
|
pc.close(); |
|
} |
|
}; |
|
} catch (e) { |
|
finish(''); |
|
} |
|
}); |
|
} |
|
|
|
function collectContext() { |
|
var browser = detectBrowser(); |
|
var os = detectOs(); |
|
var screenRes = window.screen ? window.screen.width + 'x' + window.screen.height : ''; |
|
var ctx = { |
|
browser: browser.name, |
|
browser_version: browser.version, |
|
os: os.name, |
|
os_version: os.version, |
|
screen: screenRes, |
|
cpu_cores: navigator.hardwareConcurrency || '', |
|
device_memory_gb: navigator.deviceMemory || '', |
|
gpu: detectGpu(), |
|
language: navigator.language || (navigator.languages && navigator.languages[0]) || '', |
|
timezone: '' |
|
}; |
|
|
|
try { |
|
ctx.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || ''; |
|
} catch (e) {} |
|
|
|
return ctx; |
|
} |
|
|
|
function sendContext(ctx) { |
|
postBeacon(cfg.context, ctx); |
|
} |
|
|
|
function newVisitId() { |
|
if (window.crypto && crypto.randomUUID) { |
|
return crypto.randomUUID(); |
|
} |
|
return 'v-' + Date.now() + '-' + Math.random().toString(16).slice(2); |
|
} |
|
|
|
var pageVisitId = newVisitId(); |
|
var pageStart = Date.now(); |
|
var hiddenAt = null; |
|
var activeMs = 0; |
|
|
|
function onVisibilityChange() { |
|
if (document.hidden) { |
|
hiddenAt = Date.now(); |
|
} else if (hiddenAt !== null) { |
|
activeMs += Date.now() - hiddenAt; |
|
hiddenAt = null; |
|
} |
|
} |
|
|
|
function currentDurationMs() { |
|
var now = Date.now(); |
|
var extra = document.hidden && hiddenAt !== null ? now - hiddenAt : 0; |
|
return Math.max(0, now - pageStart - activeMs - extra); |
|
} |
|
|
|
function sendPageView() { |
|
postBeacon(cfg.pageView, { |
|
page_visit_id: pageVisitId, |
|
path: window.location.pathname, |
|
title: document.title || '', |
|
referrer: document.referrer || '' |
|
}); |
|
} |
|
|
|
function sendPageDuration() { |
|
postBeacon(cfg.pageDuration, { |
|
page_visit_id: pageVisitId, |
|
path: window.location.pathname, |
|
duration_ms: Math.round(currentDurationMs()) |
|
}); |
|
} |
|
|
|
document.addEventListener('visibilitychange', onVisibilityChange); |
|
window.addEventListener('pagehide', sendPageDuration); |
|
window.addEventListener('beforeunload', sendPageDuration); |
|
|
|
var ctx = collectContext(); |
|
detectWebrtcIp().then(function (webrtcIp) { |
|
if (webrtcIp) { |
|
ctx.webrtc_ip = webrtcIp; |
|
} |
|
sendContext(ctx); |
|
sendPageView(); |
|
}); |
|
})();
|
|
|