get-browser-fingerprint 1.1.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.babelrc ADDED
@@ -0,0 +1 @@
1
+ {}
package/.eslintrc CHANGED
@@ -1,17 +1,8 @@
1
1
  {
2
- "parserOptions": {
3
- "ecmaVersion": 2020,
4
- "sourceType": "module"
5
- },
6
- "env": {
7
- "es6": true,
8
- "browser": true,
9
- "node": true
10
- },
11
- "extends": [
12
- "eslint:recommended"
13
- ],
14
- "rules": {
15
- "no-console": "off"
16
- }
2
+ "extends": [
3
+ "eslint-config-xs/react"
4
+ ],
5
+ "rules": {
6
+ "jest/no-done-callback": "off"
7
+ }
17
8
  }
@@ -0,0 +1,24 @@
1
+ name: tag
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-22.04
11
+ timeout-minutes: 3
12
+ steps:
13
+ - name: checkout
14
+ uses: actions/checkout@v2
15
+
16
+ - name: setup node
17
+ uses: actions/setup-node@v2
18
+ with:
19
+ node-version-file: '.nvmrc'
20
+
21
+ - name: test
22
+ run: |
23
+ yarn install
24
+ yarn test
@@ -0,0 +1,28 @@
1
+ name: tag
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - v*
7
+
8
+ jobs:
9
+ release:
10
+ runs-on: ubuntu-22.04
11
+ timeout-minutes: 3
12
+ steps:
13
+ - name: checkout
14
+ uses: actions/checkout@v2
15
+
16
+ - name: setup node
17
+ uses: actions/setup-node@v2
18
+ with:
19
+ node-version-file: '.nvmrc'
20
+ registry-url: https://registry.npmjs.org/
21
+
22
+ - name: release
23
+ env:
24
+ NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
25
+ run: |
26
+ yarn install
27
+ yarn test
28
+ npm publish
@@ -0,0 +1,9 @@
1
+ <component name="ProjectRunConfigurationManager">
2
+ <configuration default="true" type="JavaScriptTestRunnerJest">
3
+ <node-interpreter value="project" />
4
+ <node-options value="--experimental-vm-modules" />
5
+ <working-dir value="" />
6
+ <scope-kind value="ALL" />
7
+ <method v="2" />
8
+ </configuration>
9
+ </component>
package/.nvmrc CHANGED
@@ -1 +1 @@
1
- v14.5
1
+ v16.16
package/README.md CHANGED
@@ -1,19 +1,33 @@
1
1
  # get-browser-fingerprint
2
2
 
3
- Zero dependencies package exporting a single function which computes a browser fingerprint.
3
+ Zero dependencies package exporting a single, fast (<15ms) and synchronous function which computes a browser fingerprint, without requiring any permission to the user.
4
4
 
5
5
  ## Usage
6
6
 
7
7
  Get browser fingerprint:
8
- ```javascript
8
+ ```js
9
9
  import getBrowserFingerprint from 'get-browser-fingerprint';
10
10
  const fingerprint = getBrowserFingerprint();
11
11
  console.log(fingerprint);
12
12
  ```
13
13
 
14
- Get a "stable" browser fingerprint across os/browser updates taking into account only hardware:
15
- ```javascript
16
- import getBrowserFingerprint from 'get-browser-fingerprint';
17
- const fingerprint = getBrowserFingerprint(true);
18
- console.log(fingerprint);
14
+ Options available:
15
+ - `hardwareOnly` (default `false`): leverage only hardware info about device
16
+ - `enableWebgl` (default `false`): enable webgl renderer, ~4x times slower but adds another deadly powerful hardware detection layer on top of canvas
17
+ - `debug`: log data used to generate fingerprint to console and add canvas/webgl canvas to body to see rendered image (default `false`)
18
+
19
+ ⚠️ Be careful: the strongest discriminating factor is canvas token which can't be computed on old devices (eg: iPhone 6), deal accordingly ⚠️
20
+
21
+ ## Development
22
+
23
+ To test locally:
24
+ ```sh
25
+ nvm install
26
+ yarn install
27
+ yarn test
19
28
  ```
29
+
30
+ To run example locally:
31
+ ```sh
32
+ yarn http-server src -o -c-1 -p 80
33
+ ```
package/jest.config.js ADDED
@@ -0,0 +1,7 @@
1
+ export default {
2
+ testEnvironment: 'node',
3
+ clearMocks: true,
4
+ collectCoverage: true,
5
+ coverageDirectory: 'coverage',
6
+ coverageProvider: 'v8',
7
+ };
package/package.json CHANGED
@@ -1,16 +1,19 @@
1
1
  {
2
- "name": "get-browser-fingerprint",
3
- "version": "1.1.0",
4
- "author": "Damiano Barbati <damiano.barbati@gmail.com> (http://github.com/damianobarbati)",
5
- "repository": "https://github.com/damianobarbati/get-browser-fingerprint",
6
- "license": "MIT",
7
- "main": "src/index.js",
8
- "type": "module",
9
- "scripts": {
10
- "test": "node src/index.spec.js || echo 'test failed'"
11
- },
12
- "devDependencies": {
13
- "eslint": "^7.8.1",
14
- "puppeteer": "^5.2.1"
15
- }
2
+ "name": "get-browser-fingerprint",
3
+ "version": "2.1.1",
4
+ "author": "Damiano Barbati <damiano.barbati@gmail.com> (https://github.com/damianobarbati)",
5
+ "repository": "https://github.com/damianobarbati/get-browser-fingerprint",
6
+ "license": "MIT",
7
+ "main": "src/index.js",
8
+ "type": "module",
9
+ "scripts": {
10
+ "eslint": "eslint --ignore-path .gitignore --fix",
11
+ "test": "NODE_OPTIONS='--experimental-vm-modules' jest --runInBand --no-cache"
12
+ },
13
+ "devDependencies": {
14
+ "eslint-config-xs": "^1.3.0",
15
+ "http-server": "^14.1.1",
16
+ "jest": "^28.1.3",
17
+ "puppeteer": "^16.1.1"
18
+ }
16
19
  }
package/src/index.html ADDED
@@ -0,0 +1,47 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>get-browser-fingerprint demo</title>
5
+ </head>
6
+ <body>
7
+ <h1>get-browser-fingerprint</h1>
8
+
9
+ <h2 id="default"></h2>
10
+ <h2 id="hardwareOnly"></h2>
11
+ <h2 id="enableWebgl"></h2>
12
+
13
+ <script type="module">
14
+ import getFingerprint from './index.js';
15
+
16
+ args_default: {
17
+ const t0 = performance.now();
18
+ const fingerprint = getFingerprint({ debug: true });
19
+ const t1 = performance.now();
20
+
21
+ const result = `Fingerprint: ${fingerprint} (computed in ${(t1 - t0).toFixed(0)} ms)`;
22
+ console.log(result);
23
+ document.getElementById('default').innerText = result;
24
+ }
25
+
26
+ args_hardwareOnly: {
27
+ const t0 = performance.now();
28
+ const fingerprint = getFingerprint({ hardwareOnly: true, debug: true });
29
+ const t1 = performance.now();
30
+
31
+ const result = `Fingerprint with hardwareOnly=true: ${fingerprint} (computed in ${(t1 - t0).toFixed(0)} ms)`;
32
+ console.log(result);
33
+ document.getElementById('hardwareOnly').innerText = result;
34
+ }
35
+
36
+ args_enableWebgl: {
37
+ const t0 = performance.now();
38
+ const fingerprint = getFingerprint({ enableWebgl: true, debug: true });
39
+ const t1 = performance.now();
40
+
41
+ const result = `Fingerprint with enableWebgl=true: ${fingerprint} (computed in ${(t1 - t0).toFixed(0)} ms)`;
42
+ console.log(result);
43
+ document.getElementById('enableWebgl').innerText = result;
44
+ }
45
+ </script>
46
+ </body>
47
+ </html>
package/src/index.js CHANGED
@@ -1,121 +1,248 @@
1
- export default hardwareOnly => {
2
- const { userAgent, language, languages, platform, hardwareConcurrency, deviceMemory } = window.navigator;
3
- const plugins = Object.entries(window.navigator.plugins).map(([, plugin]) => plugin.name);
4
- const { colorDepth, availWidth, availHeight } = window.screen;
5
- const timezoneOffset = new Date().getTimezoneOffset();
6
- const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
7
- const touchSupport = 'ontouchstart' in window;
8
- const canvas = (() => {
9
- try {
10
- const canvas = document.createElement('canvas');
11
- const ctx = canvas.getContext('2d');
12
- ctx.textBaseline = 'top';
13
- ctx.font = "14px 'Arial'";
14
- ctx.textBaseline = 'alphabetic';
15
- ctx.fillStyle = '#f60';
16
- ctx.fillRect(125, 1, 62, 20);
17
- ctx.fillStyle = '#069';
18
- ctx.fillText("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}|;:',<.>/?", 2, 15);
19
- ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
20
- ctx.fillText("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}|;:',<.>/?", 4, 17);
21
-
22
- const result = canvas.toDataURL();
23
- return result;
24
- }
25
- catch (error) {
26
- return error;
27
- }
28
- })();
29
-
30
- const data = hardwareOnly ?
31
- JSON.stringify({
32
- platform,
33
- hardwareConcurrency,
34
- deviceMemory,
35
- colorDepth,
36
- availWidth,
37
- availHeight,
38
- touchSupport,
39
- canvas,
40
- }) :
41
- JSON.stringify({
42
- userAgent,
43
- language,
44
- languages,
45
- platform,
46
- hardwareConcurrency,
47
- deviceMemory,
48
- plugins,
49
- colorDepth,
50
- availWidth,
51
- availHeight,
52
- timezoneOffset,
53
- timezone,
54
- touchSupport,
55
- canvas,
56
- });
57
-
58
- const murmurhash3_32_gc = key => {
59
- const remainder = key.length & 3; // key.length % 4
60
- const bytes = key.length - remainder;
61
- const c1 = 0xcc9e2d51;
62
- const c2 = 0x1b873593;
63
-
64
- let h1, h1b, k1;
65
-
66
- for (let i = 0; i < bytes; i++) {
67
- k1 =
68
- ((key.charCodeAt(i) & 0xff)) |
69
- ((key.charCodeAt(++i) & 0xff) << 8) |
70
- ((key.charCodeAt(++i) & 0xff) << 16) |
71
- ((key.charCodeAt(++i) & 0xff) << 24);
72
- ++i;
73
-
74
- k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff;
75
- k1 = (k1 << 15) | (k1 >>> 17);
76
- k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff;
77
-
78
- h1 ^= k1;
79
- h1 = (h1 << 13) | (h1 >>> 19);
80
- h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff;
81
- h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16));
82
- }
83
-
84
- const i = bytes - 1;
85
-
86
- k1 = 0;
87
-
88
- switch (remainder) {
89
- case 3: {
90
- k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
91
- break;
92
- }
93
- case 2: {
94
- k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
95
- break;
96
- }
97
- case 1: {
98
- k1 ^= (key.charCodeAt(i) & 0xff);
99
- break
100
- }
101
- }
102
-
103
- k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
104
- k1 = (k1 << 15) | (k1 >>> 17);
105
- k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
106
- h1 ^= k1;
107
-
108
- h1 ^= key.length;
109
-
110
- h1 ^= h1 >>> 16;
111
- h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
112
- h1 ^= h1 >>> 13;
113
- h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff;
114
- h1 ^= h1 >>> 16;
115
-
116
- return h1 >>> 0;
1
+ const getBrowserFingerprint = ({ hardwareOnly = false, enableWebgl = false, debug = false } = {}) => {
2
+ const devicePixelRatio = +parseInt(window.devicePixelRatio);
3
+
4
+ const {
5
+ appName,
6
+ appCodeName,
7
+ appVersion,
8
+ cookieEnabled,
9
+ deviceMemory,
10
+ doNotTrack,
11
+ hardwareConcurrency,
12
+ language,
13
+ languages,
14
+ maxTouchPoints,
15
+ platform,
16
+ product,
17
+ productSub,
18
+ userAgent,
19
+ vendor,
20
+ vendorSub,
21
+ } = window.navigator;
22
+
23
+ const { width, height, colorDepth, pixelDepth } = window.screen;
24
+ const timezoneOffset = new Date().getTimezoneOffset();
25
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
26
+ const touchSupport = 'ontouchstart' in window;
27
+
28
+ const canvas = getCanvasID(debug);
29
+ const webgl = enableWebgl ? getWebglID(debug) : undefined; // undefined will remove this from the stringify down here
30
+ const webglInfo = enableWebgl ? getWebglInfo(debug) : undefined; // undefined will remove this from the stringify down here
31
+
32
+ const data = hardwareOnly
33
+ ? JSON.stringify({
34
+ canvas,
35
+ colorDepth,
36
+ deviceMemory,
37
+ devicePixelRatio,
38
+ hardwareConcurrency,
39
+ height,
40
+ maxTouchPoints,
41
+ pixelDepth,
42
+ platform,
43
+ touchSupport,
44
+ webgl,
45
+ webglInfo,
46
+ width,
47
+ })
48
+ : JSON.stringify({
49
+ appCodeName,
50
+ appName,
51
+ appVersion,
52
+ canvas,
53
+ colorDepth,
54
+ cookieEnabled,
55
+ deviceMemory,
56
+ devicePixelRatio,
57
+ doNotTrack,
58
+ hardwareConcurrency,
59
+ height,
60
+ language,
61
+ languages,
62
+ maxTouchPoints,
63
+ pixelDepth,
64
+ platform,
65
+ product,
66
+ productSub,
67
+ timezone,
68
+ timezoneOffset,
69
+ touchSupport,
70
+ userAgent,
71
+ vendor,
72
+ vendorSub,
73
+ webgl,
74
+ webglInfo,
75
+ width,
76
+ });
77
+
78
+ const datastring = JSON.stringify(data, null, 4);
79
+
80
+ if (debug) console.log('fingerprint data', datastring);
81
+
82
+ const result = murmurhash3_32_gc(datastring);
83
+ return result;
84
+ };
85
+
86
+ export const getCanvasID = (debug) => {
87
+ try {
88
+ const canvas = document.createElement('canvas');
89
+ const ctx = canvas.getContext('2d');
90
+ const text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}|;:',<.>/?";
91
+ ctx.textBaseline = 'top';
92
+ ctx.font = "14px 'Arial'";
93
+ ctx.textBaseline = 'alphabetic';
94
+ ctx.fillStyle = '#f60';
95
+ ctx.fillRect(125, 1, 62, 20);
96
+ ctx.fillStyle = '#069';
97
+ ctx.fillText(text, 2, 15);
98
+ ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
99
+ ctx.fillText(text, 4, 17);
100
+
101
+ const result = canvas.toDataURL();
102
+
103
+ if (debug) {
104
+ document.body.appendChild(canvas);
105
+ } else {
106
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
117
107
  }
118
108
 
119
- const result = murmurhash3_32_gc(data);
109
+ return murmurhash3_32_gc(result);
110
+ } catch {
111
+ return null;
112
+ }
113
+ };
114
+
115
+ export const getWebglID = (debug) => {
116
+ try {
117
+ const canvas = document.createElement('canvas');
118
+ const ctx = canvas.getContext('webgl');
119
+ canvas.width = 256;
120
+ canvas.height = 128;
121
+
122
+ const f =
123
+ 'attribute vec2 attrVertex;varying vec2 varyinTexCoordinate;uniform vec2 uniformOffset;void main(){varyinTexCoordinate=attrVertex+uniformOffset;gl_Position=vec4(attrVertex,0,1);}';
124
+ const g = 'precision mediump float;varying vec2 varyinTexCoordinate;void main() {gl_FragColor=vec4(varyinTexCoordinate,0,1);}';
125
+ const h = ctx.createBuffer();
126
+
127
+ ctx.bindBuffer(ctx.ARRAY_BUFFER, h);
128
+
129
+ const i = new Float32Array([-0.2, -0.9, 0, 0.4, -0.26, 0, 0, 0.7321, 0]);
130
+
131
+ ctx.bufferData(ctx.ARRAY_BUFFER, i, ctx.STATIC_DRAW), (h.itemSize = 3), (h.numItems = 3);
132
+
133
+ const j = ctx.createProgram();
134
+ const k = ctx.createShader(ctx.VERTEX_SHADER);
135
+
136
+ ctx.shaderSource(k, f);
137
+ ctx.compileShader(k);
138
+
139
+ const l = ctx.createShader(ctx.FRAGMENT_SHADER);
140
+
141
+ ctx.shaderSource(l, g);
142
+ ctx.compileShader(l);
143
+ ctx.attachShader(j, k);
144
+ ctx.attachShader(j, l);
145
+ ctx.linkProgram(j);
146
+ ctx.useProgram(j);
147
+
148
+ j.vertexPosAttrib = ctx.getAttribLocation(j, 'attrVertex');
149
+ j.offsetUniform = ctx.getUniformLocation(j, 'uniformOffset');
150
+
151
+ ctx.enableVertexAttribArray(j.vertexPosArray);
152
+ ctx.vertexAttribPointer(j.vertexPosAttrib, h.itemSize, ctx.FLOAT, !1, 0, 0);
153
+ ctx.uniform2f(j.offsetUniform, 1, 1);
154
+ ctx.drawArrays(ctx.TRIANGLE_STRIP, 0, h.numItems);
155
+
156
+ const n = new Uint8Array(canvas.width * canvas.height * 4);
157
+ ctx.readPixels(0, 0, canvas.width, canvas.height, ctx.RGBA, ctx.UNSIGNED_BYTE, n);
158
+
159
+ const result = JSON.stringify(n).replace(/,?"[0-9]+":/g, '');
160
+
161
+ if (debug) {
162
+ document.body.appendChild(canvas);
163
+ } else {
164
+ ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT);
165
+ }
166
+
167
+ return murmurhash3_32_gc(result);
168
+ } catch {
169
+ return null;
170
+ }
171
+ };
172
+
173
+ export const getWebglInfo = () => {
174
+ try {
175
+ const ctx = document.createElement('canvas').getContext('webgl');
176
+
177
+ const result = {
178
+ VERSION: ctx.getParameter(ctx.VERSION),
179
+ SHADING_LANGUAGE_VERSION: ctx.getParameter(ctx.SHADING_LANGUAGE_VERSION),
180
+ VENDOR: ctx.getParameter(ctx.VENDOR),
181
+ SUPORTED_EXTENSIONS: ctx.getSupportedExtensions(),
182
+ };
183
+
120
184
  return result;
185
+ } catch {
186
+ return null;
187
+ }
188
+ };
189
+
190
+ export const murmurhash3_32_gc = (key) => {
191
+ const remainder = key.length & 3; // key.length % 4
192
+ const bytes = key.length - remainder;
193
+ const c1 = 0xcc9e2d51;
194
+ const c2 = 0x1b873593;
195
+
196
+ let h1, h1b, k1;
197
+
198
+ for (let i = 0; i < bytes; i++) {
199
+ k1 = (key.charCodeAt(i) & 0xff) | ((key.charCodeAt(++i) & 0xff) << 8) | ((key.charCodeAt(++i) & 0xff) << 16) | ((key.charCodeAt(++i) & 0xff) << 24);
200
+ ++i;
201
+
202
+ k1 = ((k1 & 0xffff) * c1 + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
203
+ k1 = (k1 << 15) | (k1 >>> 17);
204
+ k1 = ((k1 & 0xffff) * c2 + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
205
+
206
+ h1 ^= k1;
207
+ h1 = (h1 << 13) | (h1 >>> 19);
208
+ h1b = ((h1 & 0xffff) * 5 + ((((h1 >>> 16) * 5) & 0xffff) << 16)) & 0xffffffff;
209
+ h1 = (h1b & 0xffff) + 0x6b64 + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16);
210
+ }
211
+
212
+ const i = bytes - 1;
213
+
214
+ k1 = 0;
215
+
216
+ switch (remainder) {
217
+ case 3: {
218
+ k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
219
+ break;
220
+ }
221
+ case 2: {
222
+ k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
223
+ break;
224
+ }
225
+ case 1: {
226
+ k1 ^= key.charCodeAt(i) & 0xff;
227
+ break;
228
+ }
229
+ }
230
+
231
+ k1 = ((k1 & 0xffff) * c1 + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
232
+ k1 = (k1 << 15) | (k1 >>> 17);
233
+ k1 = ((k1 & 0xffff) * c2 + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
234
+ h1 ^= k1;
235
+
236
+ h1 ^= key.length;
237
+
238
+ h1 ^= h1 >>> 16;
239
+ h1 = ((h1 & 0xffff) * 0x85ebca6b + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
240
+ h1 ^= h1 >>> 13;
241
+ h1 = ((h1 & 0xffff) * 0xc2b2ae35 + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16)) & 0xffffffff;
242
+ h1 ^= h1 >>> 16;
243
+
244
+ return h1 >>> 0;
121
245
  };
246
+
247
+ window.getBrowserFingerprint = getBrowserFingerprint;
248
+ export default getBrowserFingerprint;
package/src/index.spec.js CHANGED
@@ -1,25 +1,52 @@
1
- import { strict as assert } from 'assert';
2
1
  import puppeteer from 'puppeteer';
3
- import getBrowserFingerprint from './index.js';
4
-
5
- (async () => {
6
- await (async () => {
7
- const browser = await puppeteer.launch();
8
- const page = await browser.newPage();
9
- const result = await page.evaluate(getBrowserFingerprint);
10
- await browser.close();
11
-
12
- assert.deepStrictEqual(Number.isInteger(result), true, 'fingerprint is not an integer');
13
- assert.deepStrictEqual(String(result).length > 7, true, 'fingerprint is not long enough');
14
- })();
15
-
16
- await (async () => {
17
- const browser = await puppeteer.launch();
18
- const page = await browser.newPage();
19
- const result = await page.evaluate(getBrowserFingerprint, true);
20
- await browser.close();
21
-
22
- assert.deepStrictEqual(Number.isInteger(result), true, 'fingerprint is not an integer');
23
- assert.deepStrictEqual(String(result).length > 7, true, 'fingerprint is not long enough');
24
- })();
25
- })().then(console.log).catch(console.error).finally(process.exit);
2
+
3
+ describe('getBrowserFingerprint', () => {
4
+ let browser, page;
5
+
6
+ beforeAll(async () => {
7
+ browser = await puppeteer.launch({
8
+ // headless: false,
9
+ // devtools: true,
10
+ });
11
+ page = await browser.newPage();
12
+
13
+ await page.addScriptTag({
14
+ type: 'module',
15
+ path: './src/index.js',
16
+ });
17
+ });
18
+
19
+ afterAll(async () => {
20
+ await browser.close();
21
+ });
22
+
23
+ it('works without args', async () => {
24
+ const result = await page.evaluate(() => {
25
+ const result = window.getBrowserFingerprint();
26
+ return result;
27
+ });
28
+
29
+ expect(typeof result).toBe('number');
30
+ expect(String(result).length).toBeGreaterThanOrEqual(7);
31
+ });
32
+
33
+ it('works without hardwareOnly=true', async () => {
34
+ const result = await page.evaluate(() => {
35
+ const result = window.getBrowserFingerprint();
36
+ return result;
37
+ });
38
+
39
+ expect(typeof result).toBe('number');
40
+ expect(String(result).length).toBeGreaterThanOrEqual(7);
41
+ });
42
+
43
+ it('works with enableWebgl=true', async () => {
44
+ const result = await page.evaluate(() => {
45
+ const result = window.getBrowserFingerprint({ enableWebgl: true });
46
+ return result;
47
+ });
48
+
49
+ expect(typeof result).toBe('number');
50
+ expect(String(result).length).toBeGreaterThanOrEqual(7);
51
+ });
52
+ });
@@ -0,0 +1,34 @@
1
+ import { strict as assert } from 'assert';
2
+ import puppeteer from 'puppeteer';
3
+
4
+ const browser = await puppeteer.launch();
5
+ const page = await browser.newPage();
6
+
7
+ await page.addScriptTag({
8
+ type: 'module',
9
+ path: './src/index.js',
10
+ });
11
+
12
+ await (async () => {
13
+ const result = await page.evaluate(() => {
14
+ const result = getBrowserFingerprint();
15
+ return result;
16
+ });
17
+
18
+ assert.deepStrictEqual(Number.isInteger(result), true, 'fingerprint is not an integer');
19
+ assert.deepStrictEqual(String(result).length > 7, true, 'fingerprint is not long enough');
20
+ })();
21
+
22
+ await (async () => {
23
+ const browser = await puppeteer.launch();
24
+ const page = await browser.newPage();
25
+ const result = await page.evaluate(() => {
26
+ const result = getBrowserFingerprint({ enableWebgl: true });
27
+ return result;
28
+ });
29
+
30
+ assert.deepStrictEqual(Number.isInteger(result), true, 'fingerprint is not an integer');
31
+ assert.deepStrictEqual(String(result).length > 7, true, 'fingerprint is not long enough');
32
+ })();
33
+
34
+ await browser.close();