2023-05-21 15:54:20 +03:00
|
|
|
// reformat geo: links based on platform
|
2023-04-30 14:08:32 +03:00
|
|
|
const ua = String(platform.os).toLowerCase();
|
|
|
|
|
const android = ua.indexOf("android") > -1;
|
|
|
|
|
const ios = ua.indexOf("ios") > -1;
|
|
|
|
|
const windows = ua.indexOf("windows") > -1;
|
|
|
|
|
const linux = ua.indexOf("linux") > -1;
|
|
|
|
|
const mac = ua.indexOf("macos") > -1;
|
2023-05-01 22:59:40 +03:00
|
|
|
var hashlinks = document.querySelectorAll('[href*="geo:"]');
|
2023-05-01 21:58:23 +03:00
|
|
|
var hasharray = [...hashlinks];
|
|
|
|
|
if ( hasharray.length > 0 ) {
|
|
|
|
|
hasharray.forEach(hashlink => {
|
2023-05-01 22:59:40 +03:00
|
|
|
const geolink = hashlink.getAttribute("href").match(/(-?\d+(\.\d+)?),\s*(-?\d+(\.\d+)?)/g);
|
|
|
|
|
var latlon;
|
|
|
|
|
if ( geolink.length > 1 && geolink[0] == '0,0') latlon = geolink[1];
|
|
|
|
|
else latlon = geolink[0];
|
|
|
|
|
if ( windows || mac || linux ) hashlink.href = "https://maps.google.com/?q=" + latlon;
|
|
|
|
|
else if ( android ) hashlink.href = "geo:0,0?q=" + latlon;
|
|
|
|
|
else if ( ios ) hashlink.href = "http://maps.apple.com/?ll=" + latlon + "&q=" + hashlink.innerHTML;
|
2023-05-01 21:58:23 +03:00
|
|
|
});
|
2023-05-21 15:54:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fingerprint user
|
2023-05-21 16:11:07 +03:00
|
|
|
|
|
|
|
|
const cyrb53 = function (str, seed = 0) {
|
|
|
|
|
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
|
|
|
|
|
for (let i = 0, ch; i < str.length; i++) {
|
|
|
|
|
ch = str.charCodeAt(i);
|
|
|
|
|
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
|
|
|
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
|
|
|
}
|
|
|
|
|
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
|
|
|
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
|
|
|
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const generateTheAudioFingerPrint = function () {
|
|
|
|
|
var context = null;
|
|
|
|
|
var currentTime = null;
|
|
|
|
|
var oscillator = null;
|
|
|
|
|
var compressor = null;
|
|
|
|
|
var fingerprint = null;
|
|
|
|
|
var callback = null;
|
|
|
|
|
function run(cb, debug = false) {
|
|
|
|
|
callback = cb;
|
|
|
|
|
try {
|
|
|
|
|
setup();
|
|
|
|
|
oscillator.connect(compressor);
|
|
|
|
|
compressor.connect(context.destination);
|
|
|
|
|
oscillator.start(0);
|
|
|
|
|
context.startRendering();
|
|
|
|
|
context.oncomplete = onComplete;
|
|
|
|
|
}
|
|
|
|
|
catch (e) {
|
|
|
|
|
if (debug) {
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function setup() {
|
|
|
|
|
setContext();
|
|
|
|
|
currentTime = context.currentTime;
|
|
|
|
|
setOscillator();
|
|
|
|
|
setCompressor();
|
|
|
|
|
}
|
|
|
|
|
function setContext() {
|
|
|
|
|
var audioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext;
|
|
|
|
|
context = new audioContext(1, 44100, 44100);
|
|
|
|
|
}
|
|
|
|
|
function setOscillator() {
|
|
|
|
|
oscillator = context.createOscillator();
|
|
|
|
|
oscillator.type = "triangle";
|
|
|
|
|
oscillator.frequency.setValueAtTime(10000, currentTime);
|
|
|
|
|
}
|
|
|
|
|
function setCompressor() {
|
|
|
|
|
compressor = context.createDynamicsCompressor();
|
|
|
|
|
setCompressorValueIfDefined('threshold', -50);
|
|
|
|
|
setCompressorValueIfDefined('knee', 40);
|
|
|
|
|
setCompressorValueIfDefined('ratio', 12);
|
|
|
|
|
setCompressorValueIfDefined('reduction', -20);
|
|
|
|
|
setCompressorValueIfDefined('attack', 0);
|
|
|
|
|
setCompressorValueIfDefined('release', .25);
|
|
|
|
|
}
|
|
|
|
|
function setCompressorValueIfDefined(item, value) {
|
|
|
|
|
if (compressor[item] !== undefined && typeof compressor[item].setValueAtTime === 'function') {
|
|
|
|
|
compressor[item].setValueAtTime(value, context.currentTime);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function onComplete(event) {
|
|
|
|
|
generateFingerprints(event);
|
|
|
|
|
compressor.disconnect();
|
|
|
|
|
}
|
|
|
|
|
function generateFingerprints(event) {
|
|
|
|
|
var output = null;
|
|
|
|
|
for (var i = 4500; 5e3 > i; i++) {
|
|
|
|
|
var channelData = event.renderedBuffer.getChannelData(0)[i];
|
|
|
|
|
output += Math.abs(channelData);
|
|
|
|
|
}
|
|
|
|
|
fingerprint = output.toString();
|
|
|
|
|
if (typeof callback === 'function') {
|
|
|
|
|
return callback(fingerprint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
run: run
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getCanvasFingerprint = () => {
|
|
|
|
|
// If canvas is not supported simply return a static string
|
|
|
|
|
if (!(0, exports.isCanvasSupported)())
|
|
|
|
|
return "broprint.js";
|
|
|
|
|
// draw a canvas of given text and return its data uri
|
|
|
|
|
// different browser generates different dataUri based on their hardware configs
|
|
|
|
|
var canvas = document.createElement('canvas');
|
|
|
|
|
var ctx = canvas.getContext('2d');
|
|
|
|
|
// https://www.browserleaks.com/canvas#how-does-it-work
|
|
|
|
|
var txt = 'BroPrint.65@345876';
|
|
|
|
|
ctx.textBaseline = "top";
|
|
|
|
|
ctx.font = "14px 'Arial'";
|
|
|
|
|
ctx.textBaseline = "alphabetic";
|
|
|
|
|
ctx.fillStyle = "#f60";
|
|
|
|
|
ctx.fillRect(125, 1, 62, 20);
|
|
|
|
|
ctx.fillStyle = "#069";
|
|
|
|
|
ctx.fillText(txt, 2, 15);
|
|
|
|
|
ctx.fillStyle = "rgba(102, 204, 0, 0.7)";
|
|
|
|
|
ctx.fillText(txt, 4, 17);
|
|
|
|
|
return canvas.toDataURL();
|
|
|
|
|
};
|
|
|
|
|
|
2023-05-21 16:14:46 +03:00
|
|
|
function getCurrentBrowserFingerPrint() {
|
2023-05-21 15:54:20 +03:00
|
|
|
const getTheAudioPrints = new Promise((resolve, reject) => {
|
2023-05-21 16:02:53 +03:00
|
|
|
generateTheAudioFingerPrint.run(function (fingerprint) {
|
2023-05-21 15:54:20 +03:00
|
|
|
resolve(fingerprint);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
const DevicePrints = new Promise((resolve, reject) => {
|
|
|
|
|
getTheAudioPrints.then((audioChannelResult) => {
|
2023-05-21 16:02:53 +03:00
|
|
|
let fingerprint = window.btoa(audioChannelResult) + (0, getCanvasFingerprint)();
|
|
|
|
|
resolve((0, cyrb53)(fingerprint, 0));
|
2023-05-21 15:54:20 +03:00
|
|
|
}).catch(() => {
|
|
|
|
|
try {
|
2023-05-21 16:02:53 +03:00
|
|
|
resolve((0, cyrb53)((0, getCanvasFingerprint)()).toString());
|
2023-05-21 15:54:20 +03:00
|
|
|
}
|
|
|
|
|
catch (error) {
|
|
|
|
|
reject("Failed to generate the finger print of this browser");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return DevicePrints;
|
2023-05-21 16:16:54 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
console.log(getCurrentBrowserFingerPrint());
|