File size: 1,625 Bytes
3d7d9b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
(function() {
'use strict';

// Add imperceptible noise to canvas fingerprinting attempts
const origToDataURL = HTMLCanvasElement.prototype.toDataURL;
const origToBlob = HTMLCanvasElement.prototype.toBlob;
const origGetImageData = CanvasRenderingContext2D.prototype.getImageData;

function addNoise(ctx, canvas) {
    try {
        const w = Math.min(canvas.width, 2);
        const h = Math.min(canvas.height, 2);
        const imageData = ctx.getImageData.call(ctx, 0, 0, w, h);
        // Modify one sub-pixel by ±1
        const idx = Math.floor(Math.random() * imageData.data.length);
        imageData.data[idx] = Math.max(0, Math.min(255, imageData.data[idx] + (Math.random() > 0.5 ? 1 : -1)));
        ctx.putImageData(imageData, 0, 0);
    } catch(e) { /* cross-origin or tainted canvas */ }
}

HTMLCanvasElement.prototype.toDataURL = function() {
    const ctx = this.getContext('2d');
    if (ctx) addNoise(ctx, this);
    return origToDataURL.apply(this, arguments);
};

HTMLCanvasElement.prototype.toBlob = function() {
    const ctx = this.getContext('2d');
    if (ctx) addNoise(ctx, this);
    return origToBlob.apply(this, arguments);
};

CanvasRenderingContext2D.prototype.getImageData = function() {
    const result = origGetImageData.apply(this, arguments);
    // Add noise to returned data for fingerprint resistance
    if (result.data.length > 4) {
        const idx = Math.floor(Math.random() * result.data.length);
        result.data[idx] = Math.max(0, Math.min(255, result.data[idx] + (Math.random() > 0.5 ? 1 : -1)));
    }
    return result;
};
})();