(async () => { const hashMini = x => { if (!x) return x const json = `${JSON.stringify(x)}` const hash = json.split('').reduce((hash, char, i) => { return Math.imul(31, hash) + json.charCodeAt(i) | 0 }, 0x811c9dc5) return ('0000000' + (hash >>> 0).toString(16)).substr(-8) } // template views const patch = (oldEl, newEl) => oldEl.parentNode.replaceChild(newEl, oldEl) const html = (str, ...expressionSet) => { const template = document.createElement('template') template.innerHTML = str.map((s, i) => `${s}${expressionSet[i] || ''}`).join('') return document.importNode(template.content, true) } const query = ({ type, rangeStart, rangeLen }) => { const el = document.getElementById('fingerprint-data') patch(el, html`
`) const style = getComputedStyle(document.body) return style.getPropertyValue(`--device-${type}`).trim() } const match = ({ type, rangeStart, rangeLen }) => { let found ;[...Array(rangeLen)].find((slot, i) => { i += rangeStart const { matches } = matchMedia(`(device-${type}:${i}px)`) || {} if (matches) { found = i } return matches }) return +found } const getScreenMedia = ({ width, height }) => { let widthMatch = query({ type: 'width', rangeStart: width, rangeLen: 1 }) let heightMatch = query({ type: 'height', rangeStart: height, rangeLen: 1 }) if (widthMatch && heightMatch) { return { width, height } } const rangeLen = 1000 ;[...Array(10)].find((slot, i) => { if (!widthMatch) { widthMatch = query({ type: 'width', rangeStart: i * rangeLen, rangeLen }) } if (!heightMatch) { heightMatch = query({ type: 'height', rangeStart: i * rangeLen, rangeLen }) } return widthMatch && heightMatch }) return { width: +widthMatch, height: +heightMatch } } const getScreenMatchMedia = ({ width, height }) => { let widthMatch = matchMedia(`(device-width:${width}px)`).matches let heightMatch = matchMedia(`(device-height:${height}px)`).matches if (widthMatch && heightMatch) { return { width, height } } const rangeLen = 1000 ;[...Array(10)].find((slot, i) => { if (!widthMatch) { widthMatch = match({ type: 'width', rangeStart: i * rangeLen, rangeLen }) } if (!heightMatch) { heightMatch = match({ type: 'height', rangeStart: i * rangeLen, rangeLen }) } return widthMatch && heightMatch }) return { width: +widthMatch, height: +heightMatch } } const getCSS = () => { const gcd = (a, b) => b == 0 ? a : gcd(b, a % b) const { innerWidth, innerHeight } = window const { width: screenWidth, height: screenHeight } = screen const ratio = gcd(innerWidth, innerHeight) const screenRatio = gcd(screenWidth, screenHeight) const aspectRatio = `${innerWidth / ratio}/${innerHeight / ratio}` const deviceAspectRatio = `${screenWidth / screenRatio}/${screenHeight / screenRatio}` const el = document.getElementById('fingerprint-data') patch(el, html`
`) const { width: domRectWidth, height: domRectHeight } = document.body.getBoundingClientRect() const style = getComputedStyle(document.body) return { domRectViewport: [domRectWidth, domRectHeight], viewport: style.getPropertyValue('--viewport').trim() || undefined, viewportAspectRatio: style.getPropertyValue('--viewport-aspect-ratio').trim() || undefined, deviceAspectRatio: style.getPropertyValue('--device-aspect-ratio').trim() || undefined, deviceScreen: style.getPropertyValue('--device-screen').trim() || undefined, orientation: style.getPropertyValue('--orientation').trim() || undefined, displayMode: style.getPropertyValue('--display-mode').trim() || undefined } } const start = performance.now() const { width, height, availWidth, availHeight, colorDepth, pixelDepth, } = screen const { clientHeight, clientWidth } = document.documentElement const { type: orientationType } = screen.orientation || {} const vViewport = 'visualViewport' in window ? visualViewport : {} const { width: viewportWidth, height: viewportHeight } = vViewport const { width: mediaWidth, height: mediaHeight } = getScreenMedia({ width, height }) const { width: matchMediaWidth, height: matchMediaHeight } = getScreenMatchMedia({ width, height }) const { domRectViewport, viewport, viewportAspectRatio, deviceAspectRatio, deviceScreen, orientation, displayMode } = getCSS() const style = (a, b) => b.map((char, i) => char != a[i] ? `${char}` : char).join('') const note = { unsupported: 'unsupported', blocked: 'blocked', lied: 'lied' } const pad = x => x.padStart(22, '.') const fake = () => `fake screen` const el = document.getElementById('fingerprint-data') patch(el, html`
Screen
${hashMini({ mediaWidth, mediaHeight })}
${(performance.now() - start).toFixed(2)}ms
${pad('@media search')}: ${ mediaWidth && mediaHeight ? `${'' + mediaWidth} x ${'' + mediaHeight}` : 'failed' }
${pad('matchMedia search')}: ${ matchMediaWidth && matchMediaHeight ? `${'' + matchMediaWidth} x ${'' + matchMediaHeight}` : 'failed' }
${pad('@media device')}: ${deviceScreen ? '' + deviceScreen : 'failed'}
${pad('device-aspect-ratio')}: ${deviceAspectRatio ? '' + deviceAspectRatio : 'failed'}
${pad('aspect-ratio')}: ${'' + viewportAspectRatio}
${pad('screen')}: ${ style(('' + mediaWidth).split(''), ('' + width).split(''))} x ${style(('' + mediaHeight).split(''), ('' + height).split('')) }
${pad('avail')}: ${'' + availWidth} x ${'' + availHeight}${ availWidth > width || availHeight > height ? 'out of bounds' : '' }
${pad('client')}: ${ style(('' + Math.round(domRectViewport[0])).split(''), ('' + clientWidth).split('')) } x ${'' + clientHeight} ${ clientWidth > width || clientHeight > height ? 'out of bounds' : '' }
${pad('inner')}: ${ style(('' + Math.round(domRectViewport[0])).split(''), ('' + innerWidth).split('')) } x ${'' + innerHeight} ${ innerWidth > width || innerHeight > height ? 'out of bounds' : '' }
${pad('outer')}: ${'' + outerWidth} x ${'' + outerHeight}${ outerWidth > width ? 'out of bounds' : '' }
${pad('@media viewport')}: ${'' + viewport}
${pad('dom rect viewport')}: ${'' + domRectViewport.join(' x ')}
${pad('visualViewport')}: ${viewportWidth && viewportHeight ? `${'' + viewportWidth} x ${'' + viewportHeight}` : note.unsupported}
${pad('colorDepth')}: ${'' + colorDepth}
${pad('pixelDepth')}: ${'' + pixelDepth}
${pad('devicePixelRatio')}: ${'' + devicePixelRatio}
${pad('orientation type')}: ${'' + orientationType}
${pad('@media orientation')}: ${'' + orientation}
${pad('@media display-mode')}: ${'' + displayMode}
`) })()