Created
March 5, 2023 11:29
-
-
Save mike-at-redspace/3e17bb344f6030f22a09ec13f9eac2c9 to your computer and use it in GitHub Desktop.
getCanvasFingerprint
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sha256 from 'crypto-js/sha256'; | |
import Regl from 'regl'; | |
const signals = { | |
pixelRatio: window.devicePixelRatio || 1, | |
userAgent: window.navigator.userAgent, | |
language: window.navigator.language, | |
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, | |
screenWidth: window.screen.width, | |
screenHeight: window.screen.height, | |
availScreenWidth: window.screen.availWidth, | |
availScreenHeight: window.screen.availHeight, | |
touchSupport: 'ontouchstart' in window || navigator.msMaxTouchPoints > 0, | |
cookieEnabled: navigator.cookieEnabled, | |
localStorageEnabled: (() => { | |
try { | |
localStorage.setItem('test', 'test'); | |
localStorage.removeItem('test'); | |
return true; | |
} catch (e) { | |
return false; | |
} | |
})(), | |
sessionStorageEnabled: (() => { | |
try { | |
sessionStorage.setItem('test', 'test'); | |
sessionStorage.removeItem('test'); | |
return true; | |
} catch (e) { | |
return false; | |
} | |
})(), | |
doNotTrack: navigator.doNotTrack, | |
plugins: (() => { | |
if (navigator.plugins) { | |
return Array.from(navigator.plugins).map((plugin) => plugin.name); | |
} | |
return null; | |
})(), | |
fonts: (() => { | |
const fonts = []; | |
const container = document.createElement('span'); | |
container.style.fontSize = '72px'; | |
container.innerHTML = 'abcdefghijklmnopqrstuvwxyz0123456789'; | |
const defaultWidth = container.offsetWidth; | |
const defaultHeight = container.offsetHeight; | |
const fontList = [ | |
'monospace', | |
'serif', | |
'sans-serif', | |
'cursive', | |
'fantasy', | |
'system-ui', | |
'-apple-system', | |
'BlinkMacSystemFont', | |
'Segoe UI', | |
]; | |
fontList.forEach((font) => { | |
container.style.fontFamily = font; | |
const width = container.offsetWidth; | |
const height = container.offsetHeight; | |
if (width !== defaultWidth || height !== defaultHeight) { | |
fonts.push(font); | |
} | |
}); | |
return fonts.length ? fonts : null; | |
})(), | |
}; | |
function getCanvasFingerprint() { | |
const canvas = document.createElement('canvas'); | |
const ctx = canvas.getContext('2d'); | |
canvas.width = 200; | |
canvas.height = 200; | |
let hash = ''; | |
try { | |
const regl = Regl(canvas); | |
const drawCircle = regl({ | |
frag: ` | |
precision mediump float; | |
varying vec4 color; | |
void main() { | |
gl_FragColor = color; | |
} | |
`, | |
vert: ` | |
precision mediump float; | |
attribute vec2 position; | |
attribute vec4 color; | |
varying vec4 vColor; | |
void main() { | |
gl_Position = vec4(position, 0.0, 1.0); | |
vColor = color; | |
} | |
`, | |
attributes: { | |
position: [ | |
[-1, -1], | |
[1, -1], | |
[1, 1], | |
[-1, 1], | |
], | |
color: [ | |
[1, 0, 0, 1], | |
[0, 1, 0, 1], | |
[0, 0, 1, 1], | |
[1, 1, 1, 1], | |
], | |
}, | |
elements: [ | |
[0, 1, 2], | |
[0, 2, 3], | |
], | |
}); | |
drawCircle(); | |
const drawGradient = regl({ | |
frag: ` | |
precision mediump float; | |
varying vec2 uv; | |
void main() { | |
gl_FragColor = vec4(uv, 0.0, 1.0); | |
} | |
`, | |
vert: ` | |
precision mediump float; | |
attribute vec2 position; | |
varying vec2 uv; | |
void main() { | |
gl_Position = vec4(position, 0.0, 1.0); | |
uv = position * 0.5 + 0.5; | |
} | |
`, | |
attributes: { | |
position: [ | |
[-1, -1], | |
[1, -1], | |
[1, 1], | |
[-1, 1], | |
], | |
}, | |
elements: [ | |
[0, 1, 2], | |
[0, 2, 3], | |
], | |
}); | |
drawGradient(); | |
const dataURL = canvas.toDataURL(); | |
hash = sha256(dataURL + JSON.stringify(signals)).toString(); | |
} catch (e) { | |
ctx.fillStyle = "white"; | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
ctx.fillStyle = "black"; | |
ctx.font = "20px sans-serif"; | |
ctx.fillText("Hello, world!", 50, 50); | |
const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height); | |
gradient.addColorStop(0, "red"); | |
gradient.addColorStop(1, "blue"); | |
ctx.fillStyle = gradient; | |
const dataURL = canvas.toDataURL(); | |
hash = sha256(dataURL + JSON.stringify(signals)).toString(); | |
} | |
return hash; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment