feat: 60s new-user probe — browser/OS/screen/geo/session fingerprint posted to chat webhook
This commit is contained in:
+236
@@ -1961,6 +1961,8 @@
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
})();
|
})();
|
||||||
|
/* expose for the 60-second probe script */
|
||||||
|
window._mbsChatId = CHAT_ID;
|
||||||
|
|
||||||
var panel = document.getElementById("chat-panel");
|
var panel = document.getElementById("chat-panel");
|
||||||
var chatLog = document.getElementById("chat-history");
|
var chatLog = document.getElementById("chat-history");
|
||||||
@@ -2121,6 +2123,240 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- ── 60-Second New-User Probe ──────────────────────────────────── -->
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var CHAT_URL =
|
||||||
|
"https://002-001-5dd6e535-4d1c-46bc-9bd9-42ad4bc5f082.odoo4projects.com/webhook/702862fd-dd17-4a34-8efb-e9056d2c50df/chat";
|
||||||
|
var GEO_URL = "https://ipinfo.io/json";
|
||||||
|
var fired = false;
|
||||||
|
|
||||||
|
/* ── Which section is closest to viewport centre ─────────── */
|
||||||
|
function visibleSection() {
|
||||||
|
var els = [].slice.call(
|
||||||
|
document.querySelectorAll("section[id], footer"),
|
||||||
|
);
|
||||||
|
var mid = window.innerHeight / 2;
|
||||||
|
var best = null,
|
||||||
|
bestDist = Infinity;
|
||||||
|
els.forEach(function (el) {
|
||||||
|
var r = el.getBoundingClientRect();
|
||||||
|
if (r.bottom <= 0 || r.top >= window.innerHeight)
|
||||||
|
return;
|
||||||
|
var d = Math.abs(r.top + r.height / 2 - mid);
|
||||||
|
if (d < bestDist) {
|
||||||
|
bestDist = d;
|
||||||
|
best = el;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!best) return "(top of page)";
|
||||||
|
var names = {
|
||||||
|
home: "Hero — main headline",
|
||||||
|
verticals: "Our Verticals section",
|
||||||
|
news: "News / Insights section",
|
||||||
|
pricing: "Pricing section",
|
||||||
|
customization: "Customization section",
|
||||||
|
};
|
||||||
|
return names[best.id] || best.id || "footer";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Scroll depth 0–100 % ───────────────────────────────── */
|
||||||
|
function scrollDepth() {
|
||||||
|
var d = document.documentElement;
|
||||||
|
var max = d.scrollHeight - window.innerHeight;
|
||||||
|
if (max <= 0) return 0;
|
||||||
|
return Math.min(
|
||||||
|
100,
|
||||||
|
Math.round((window.pageYOffset / max) * 100),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── UA parsers ─────────────────────────────────────────── */
|
||||||
|
function parseOS(ua) {
|
||||||
|
if (/Windows NT 10|Windows NT 11/.test(ua))
|
||||||
|
return "Windows 10/11";
|
||||||
|
if (/Windows NT 6\.3/.test(ua)) return "Windows 8.1";
|
||||||
|
if (/Windows NT 6\.1/.test(ua)) return "Windows 7";
|
||||||
|
if (/Mac OS X ([\d_]+)/.test(ua))
|
||||||
|
return "macOS " + RegExp.$1.replace(/_/g, ".");
|
||||||
|
if (/Android ([\d.]+)/.test(ua))
|
||||||
|
return "Android " + RegExp.$1;
|
||||||
|
if (/iPhone.*OS ([\d_]+)/.test(ua))
|
||||||
|
return "iOS " + RegExp.$1.replace(/_/g, ".");
|
||||||
|
if (/iPad.*OS ([\d_]+)/.test(ua))
|
||||||
|
return "iPadOS " + RegExp.$1.replace(/_/g, ".");
|
||||||
|
if (/Linux/.test(ua)) return "Linux";
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
function parseBrowser(ua) {
|
||||||
|
if (/Edg\/([\d.]+)/.test(ua)) return "Edge " + RegExp.$1;
|
||||||
|
if (/OPR\/([\d.]+)/.test(ua)) return "Opera " + RegExp.$1;
|
||||||
|
if (/Firefox\/([\d.]+)/.test(ua))
|
||||||
|
return "Firefox " + RegExp.$1;
|
||||||
|
if (/Chrome\/([\d.]+)/.test(ua))
|
||||||
|
return "Chrome " + RegExp.$1;
|
||||||
|
if (/Version\/([\d.]+).*Safari/.test(ua))
|
||||||
|
return "Safari " + RegExp.$1;
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
function deviceType(ua) {
|
||||||
|
if (/iPad|Tablet/.test(ua)) return "Tablet";
|
||||||
|
if (/Mobi|Android/.test(ua)) return "Mobile";
|
||||||
|
return "Desktop";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Label helper (fixed-width key) ─────────────────────── */
|
||||||
|
function r(label, value) {
|
||||||
|
var k = (label + ": ").slice(0, 14);
|
||||||
|
return k + " " + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Build message text ─────────────────────────────────── */
|
||||||
|
function buildMsg(geo) {
|
||||||
|
var ua = navigator.userAgent;
|
||||||
|
var conn =
|
||||||
|
navigator.connection ||
|
||||||
|
navigator.mozConnection ||
|
||||||
|
navigator.webkitConnection ||
|
||||||
|
null;
|
||||||
|
var tz =
|
||||||
|
typeof Intl !== "undefined"
|
||||||
|
? Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||||
|
: "unknown";
|
||||||
|
var langs = (
|
||||||
|
navigator.languages || [navigator.language]
|
||||||
|
).join(", ");
|
||||||
|
|
||||||
|
var lines = [
|
||||||
|
"NEW USER — 60s Probe",
|
||||||
|
"================================",
|
||||||
|
"",
|
||||||
|
r("Viewing", visibleSection()),
|
||||||
|
r("Scroll depth", scrollDepth() + "%"),
|
||||||
|
r("Time on page", "60 seconds"),
|
||||||
|
r("Timestamp", new Date().toUTCString()),
|
||||||
|
"",
|
||||||
|
"--- BROWSER & DEVICE ----------",
|
||||||
|
r("Browser", parseBrowser(ua)),
|
||||||
|
r("OS", parseOS(ua)),
|
||||||
|
r("Device", deviceType(ua)),
|
||||||
|
r("Language", navigator.language + " [" + langs + "]"),
|
||||||
|
r(
|
||||||
|
"Screen",
|
||||||
|
screen.width +
|
||||||
|
"x" +
|
||||||
|
screen.height +
|
||||||
|
" @ " +
|
||||||
|
screen.colorDepth +
|
||||||
|
"-bit",
|
||||||
|
),
|
||||||
|
r(
|
||||||
|
"Viewport",
|
||||||
|
window.innerWidth + "x" + window.innerHeight,
|
||||||
|
),
|
||||||
|
r(
|
||||||
|
"CPU cores",
|
||||||
|
String(navigator.hardwareConcurrency || "?"),
|
||||||
|
),
|
||||||
|
r(
|
||||||
|
"Device RAM",
|
||||||
|
navigator.deviceMemory
|
||||||
|
? navigator.deviceMemory + " GB"
|
||||||
|
: "?",
|
||||||
|
),
|
||||||
|
r("Touch pts", String(navigator.maxTouchPoints || 0)),
|
||||||
|
r("Cookies", navigator.cookieEnabled ? "yes" : "no"),
|
||||||
|
r("DNT", navigator.doNotTrack === "1" ? "on" : "off"),
|
||||||
|
r("User Agent", ua),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (conn) {
|
||||||
|
lines.push(
|
||||||
|
r(
|
||||||
|
"Connection",
|
||||||
|
(conn.effectiveType || "?") +
|
||||||
|
(conn.downlink
|
||||||
|
? " @ " + conn.downlink + " Mbps"
|
||||||
|
: ""),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (conn.saveData) lines.push(r("Data saver", "on"));
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push("");
|
||||||
|
lines.push("--- PAGE ----------------------");
|
||||||
|
lines.push(r("URL", window.location.href));
|
||||||
|
lines.push(
|
||||||
|
r("Referrer", document.referrer || "direct / none"),
|
||||||
|
);
|
||||||
|
lines.push(r("Title", document.title));
|
||||||
|
lines.push(r("Timezone", tz));
|
||||||
|
|
||||||
|
if (geo) {
|
||||||
|
lines.push("");
|
||||||
|
lines.push("--- LOCATION (IP API) ---------");
|
||||||
|
lines.push(r("IP", geo.ip || "?"));
|
||||||
|
lines.push(r("Country", geo.country || "?"));
|
||||||
|
if (geo.city) lines.push(r("City", geo.city));
|
||||||
|
if (geo.region) lines.push(r("Region", geo.region));
|
||||||
|
if (geo.org) lines.push(r("ISP/Org", geo.org));
|
||||||
|
if (geo.timezone) lines.push(r("IP TZ", geo.timezone));
|
||||||
|
if (geo.loc) lines.push(r("Coords", geo.loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push("");
|
||||||
|
lines.push("--- SESSION -------------------");
|
||||||
|
lines.push(r("Chat ID", window._mbsChatId || "unknown"));
|
||||||
|
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Post to webhook ─────────────────────────────────────── */
|
||||||
|
function fire(geo) {
|
||||||
|
if (fired) return;
|
||||||
|
fired = true;
|
||||||
|
var chatId =
|
||||||
|
window._mbsChatId ||
|
||||||
|
"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
|
||||||
|
/[xy]/g,
|
||||||
|
function (c) {
|
||||||
|
var r2 = (Math.random() * 16) | 0;
|
||||||
|
return (
|
||||||
|
c === "x" ? r2 : (r2 & 0x3) | 0x8
|
||||||
|
).toString(16);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
fetch(CHAT_URL, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify([
|
||||||
|
{
|
||||||
|
action: "sendMessage",
|
||||||
|
chatid: chatId,
|
||||||
|
chatInput: buildMsg(geo),
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
}).catch(function () {}); /* silently ignore errors */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Schedule: 60 seconds after page load ────────────────── */
|
||||||
|
setTimeout(function () {
|
||||||
|
fetch(GEO_URL)
|
||||||
|
.then(function (res) {
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.then(function (data) {
|
||||||
|
fire(data);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
fire(null);
|
||||||
|
});
|
||||||
|
}, 60000);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
var WEBHOOK =
|
var WEBHOOK =
|
||||||
|
|||||||
Reference in New Issue
Block a user