-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontent-detect.js
More file actions
110 lines (98 loc) · 3.5 KB
/
content-detect.js
File metadata and controls
110 lines (98 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Exposed — Content Script (MAIN world)
// Monkey-patches fingerprinting and geolocation APIs to detect usage
(function () {
"use strict";
const CHANNEL = "__exposed_detection__";
function notify(type, evidence) {
window.postMessage({ channel: CHANNEL, type, evidence }, "*");
}
// --- Canvas fingerprinting ---
// Any call to toDataURL/toBlob is suspicious — legitimate use is rare outside
// fingerprinting. Deduplication in the bridge prevents repeat noise.
const origToDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function (...args) {
notify("fingerprint-detected", "your device identified via canvas");
return origToDataURL.apply(this, args);
};
const origToBlob = HTMLCanvasElement.prototype.toBlob;
HTMLCanvasElement.prototype.toBlob = function (...args) {
notify("fingerprint-detected", "your device identified via canvas");
return origToBlob.apply(this, args);
};
// --- WebGL fingerprinting ---
function patchWebGL(proto) {
if (!proto) return;
const origGetParam = proto.getParameter;
if (origGetParam) {
proto.getParameter = function (pname) {
// RENDERER, VENDOR, UNMASKED_RENDERER, UNMASKED_VENDOR
const suspectParams = [0x1f01, 0x1f00, 0x9245, 0x9246];
if (suspectParams.includes(pname)) {
notify("fingerprint-detected", "your device identified via WebGL");
}
return origGetParam.apply(this, arguments);
};
}
const origGetExtension = proto.getExtension;
if (origGetExtension) {
proto.getExtension = function (name) {
if (name === "WEBGL_debug_renderer_info") {
notify(
"fingerprint-detected",
"your device identified via WebGL"
);
}
return origGetExtension.apply(this, arguments);
};
}
}
try {
patchWebGL(WebGLRenderingContext.prototype);
} catch (e) {}
try {
patchWebGL(WebGL2RenderingContext.prototype);
} catch (e) {}
// --- AudioContext fingerprinting ---
// OfflineAudioContext is used for audio fingerprinting but also by legitimate
// audio/video platforms (LiveKit, Zoom, etc.). We send a separate message type
// so the service worker can check if the page has tracker scripts before flagging.
try {
const origOfflineCreateOscillator =
OfflineAudioContext.prototype.createOscillator;
let offlineNotified = false;
OfflineAudioContext.prototype.createOscillator = function (...args) {
if (!offlineNotified) {
offlineNotified = true;
notify(
"audio-fingerprint-maybe",
"your device identified via audio"
);
}
return origOfflineCreateOscillator.apply(this, args);
};
} catch (e) {}
// --- Geolocation ---
if (navigator.geolocation) {
const origGetCurrentPosition =
navigator.geolocation.getCurrentPosition.bind(navigator.geolocation);
navigator.geolocation.getCurrentPosition = function (
success,
error,
options
) {
notify("geolocation-detected", "this page requested your GPS location");
return origGetCurrentPosition(success, error, options);
};
const origWatchPosition = navigator.geolocation.watchPosition.bind(
navigator.geolocation
);
navigator.geolocation.watchPosition = function (
success,
error,
options
) {
notify("geolocation-detected", "this page is tracking your GPS location");
return origWatchPosition(success, error, options);
};
}
})();