@ginger-ai/ginger-js 0.0.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.
Files changed (186) hide show
  1. package/README.md +88 -0
  2. package/dist/ginger.cjs.js +2 -0
  3. package/dist/ginger.cjs.js.map +1 -0
  4. package/dist/ginger.esm.d.ts +294 -0
  5. package/dist/ginger.esm.js +2 -0
  6. package/dist/ginger.esm.js.map +1 -0
  7. package/dist/ginger.umd.js +2 -0
  8. package/dist/ginger.umd.js.map +1 -0
  9. package/dist/types/behaviour/index.d.ts +49 -0
  10. package/dist/types/behaviour/index.d.ts.map +1 -0
  11. package/dist/types/client/index.d.ts +35 -0
  12. package/dist/types/client/index.d.ts.map +1 -0
  13. package/dist/types/core/constants.d.ts +5 -0
  14. package/dist/types/core/constants.d.ts.map +1 -0
  15. package/dist/types/core/dto/bot-detector.dto.d.ts +30 -0
  16. package/dist/types/core/dto/bot-detector.dto.d.ts.map +1 -0
  17. package/dist/types/core/dto/device-detector.dto.d.ts +54 -0
  18. package/dist/types/core/dto/device-detector.dto.d.ts.map +1 -0
  19. package/dist/types/core/dto/fingerprint.dto.d.ts +29 -0
  20. package/dist/types/core/dto/fingerprint.dto.d.ts.map +1 -0
  21. package/dist/types/core/dto/ginger.dto.d.ts +73 -0
  22. package/dist/types/core/dto/ginger.dto.d.ts.map +1 -0
  23. package/dist/types/core/dto/incognito-detector.dto.d.ts +4 -0
  24. package/dist/types/core/dto/incognito-detector.dto.d.ts.map +1 -0
  25. package/dist/types/core/dto/index.d.ts +10 -0
  26. package/dist/types/core/dto/index.d.ts.map +1 -0
  27. package/dist/types/core/dto/metrics.dto.d.ts +19 -0
  28. package/dist/types/core/dto/metrics.dto.d.ts.map +1 -0
  29. package/dist/types/core/dto/os-detector.dto.d.ts +6 -0
  30. package/dist/types/core/dto/os-detector.dto.d.ts.map +1 -0
  31. package/dist/types/core/dto/tor-detector.dto.d.ts +5 -0
  32. package/dist/types/core/dto/tor-detector.dto.d.ts.map +1 -0
  33. package/dist/types/core/helpers.d.ts +8 -0
  34. package/dist/types/core/helpers.d.ts.map +1 -0
  35. package/dist/types/core/http/httpClient.d.ts +28 -0
  36. package/dist/types/core/http/httpClient.d.ts.map +1 -0
  37. package/dist/types/core/http/request.d.ts +4 -0
  38. package/dist/types/core/http/request.d.ts.map +1 -0
  39. package/dist/types/core/index.d.ts +6 -0
  40. package/dist/types/core/index.d.ts.map +1 -0
  41. package/dist/types/core/util/error.d.ts +25 -0
  42. package/dist/types/core/util/error.d.ts.map +1 -0
  43. package/dist/types/core/util/generate-requestid.d.ts +2 -0
  44. package/dist/types/core/util/generate-requestid.d.ts.map +1 -0
  45. package/dist/types/device/components/audio/audio.d.ts +2 -0
  46. package/dist/types/device/components/audio/audio.d.ts.map +1 -0
  47. package/dist/types/device/components/canvas/canvas.d.ts +3 -0
  48. package/dist/types/device/components/canvas/canvas.d.ts.map +1 -0
  49. package/dist/types/device/components/extra/extra.d.ts +19 -0
  50. package/dist/types/device/components/extra/extra.d.ts.map +1 -0
  51. package/dist/types/device/components/fonts/fonts.d.ts +3 -0
  52. package/dist/types/device/components/fonts/fonts.d.ts.map +1 -0
  53. package/dist/types/device/components/hardware/hardware.d.ts +2 -0
  54. package/dist/types/device/components/hardware/hardware.d.ts.map +1 -0
  55. package/dist/types/device/components/index.d.ts +15 -0
  56. package/dist/types/device/components/index.d.ts.map +1 -0
  57. package/dist/types/device/components/locales/locales.d.ts +2 -0
  58. package/dist/types/device/components/locales/locales.d.ts.map +1 -0
  59. package/dist/types/device/components/math/math.d.ts +2 -0
  60. package/dist/types/device/components/math/math.d.ts.map +1 -0
  61. package/dist/types/device/components/permissions/permissions.d.ts +3 -0
  62. package/dist/types/device/components/permissions/permissions.d.ts.map +1 -0
  63. package/dist/types/device/components/plugins/plugins.d.ts +3 -0
  64. package/dist/types/device/components/plugins/plugins.d.ts.map +1 -0
  65. package/dist/types/device/components/screen/screen.d.ts +2 -0
  66. package/dist/types/device/components/screen/screen.d.ts.map +1 -0
  67. package/dist/types/device/components/screen/screenResolution.d.ts +16 -0
  68. package/dist/types/device/components/screen/screenResolution.d.ts.map +1 -0
  69. package/dist/types/device/components/system/browser.d.ts +22 -0
  70. package/dist/types/device/components/system/browser.d.ts.map +1 -0
  71. package/dist/types/device/components/system/emoji.d.ts +2 -0
  72. package/dist/types/device/components/system/emoji.d.ts.map +1 -0
  73. package/dist/types/device/components/system/system.d.ts +2 -0
  74. package/dist/types/device/components/system/system.d.ts.map +1 -0
  75. package/dist/types/device/components/webgl/imageHash.d.ts +3 -0
  76. package/dist/types/device/components/webgl/imageHash.d.ts.map +1 -0
  77. package/dist/types/device/components/webgl/webgl.d.ts +54 -0
  78. package/dist/types/device/components/webgl/webgl.d.ts.map +1 -0
  79. package/dist/types/device/factory.d.ts +26 -0
  80. package/dist/types/device/factory.d.ts.map +1 -0
  81. package/dist/types/device/index.d.ts +61 -0
  82. package/dist/types/device/index.d.ts.map +1 -0
  83. package/dist/types/device/modules/bot.d.ts +9 -0
  84. package/dist/types/device/modules/bot.d.ts.map +1 -0
  85. package/dist/types/device/modules/browserDetails.d.ts +6 -0
  86. package/dist/types/device/modules/browserDetails.d.ts.map +1 -0
  87. package/dist/types/device/modules/device/analyze-data.d.ts +7 -0
  88. package/dist/types/device/modules/device/analyze-data.d.ts.map +1 -0
  89. package/dist/types/device/modules/device/gather-data.d.ts +6 -0
  90. package/dist/types/device/modules/device/gather-data.d.ts.map +1 -0
  91. package/dist/types/device/modules/device/helpers.d.ts +9 -0
  92. package/dist/types/device/modules/device/helpers.d.ts.map +1 -0
  93. package/dist/types/device/modules/device/index.d.ts +3 -0
  94. package/dist/types/device/modules/device/index.d.ts.map +1 -0
  95. package/dist/types/device/modules/fp.d.ts +14 -0
  96. package/dist/types/device/modules/fp.d.ts.map +1 -0
  97. package/dist/types/device/modules/incognito.d.ts +7 -0
  98. package/dist/types/device/modules/incognito.d.ts.map +1 -0
  99. package/dist/types/device/modules/options.d.ts +12 -0
  100. package/dist/types/device/modules/options.d.ts.map +1 -0
  101. package/dist/types/device/modules/os.d.ts +3 -0
  102. package/dist/types/device/modules/os.d.ts.map +1 -0
  103. package/dist/types/device/modules/tor.d.ts +4 -0
  104. package/dist/types/device/modules/tor.d.ts.map +1 -0
  105. package/dist/types/device/utils/async.d.ts +33 -0
  106. package/dist/types/device/utils/async.d.ts.map +1 -0
  107. package/dist/types/device/utils/browser_.d.ts +103 -0
  108. package/dist/types/device/utils/browser_.d.ts.map +1 -0
  109. package/dist/types/device/utils/commonPixels.d.ts +2 -0
  110. package/dist/types/device/utils/commonPixels.d.ts.map +1 -0
  111. package/dist/types/device/utils/data.d.ts +33 -0
  112. package/dist/types/device/utils/data.d.ts.map +1 -0
  113. package/dist/types/device/utils/dom.d.ts +26 -0
  114. package/dist/types/device/utils/dom.d.ts.map +1 -0
  115. package/dist/types/device/utils/ephemeralIFrame.d.ts +5 -0
  116. package/dist/types/device/utils/ephemeralIFrame.d.ts.map +1 -0
  117. package/dist/types/device/utils/getMostFrequent.d.ts +6 -0
  118. package/dist/types/device/utils/getMostFrequent.d.ts.map +1 -0
  119. package/dist/types/device/utils/hash.d.ts +6 -0
  120. package/dist/types/device/utils/hash.d.ts.map +1 -0
  121. package/dist/types/device/utils/misc.d.ts +7 -0
  122. package/dist/types/device/utils/misc.d.ts.map +1 -0
  123. package/dist/types/device/utils/raceAll.d.ts +9 -0
  124. package/dist/types/device/utils/raceAll.d.ts.map +1 -0
  125. package/dist/types/index.d.ts +4 -0
  126. package/dist/types/index.d.ts.map +1 -0
  127. package/package.json +52 -0
  128. package/src/behaviour/index.ts +279 -0
  129. package/src/client/index.ts +132 -0
  130. package/src/core/constants.ts +4 -0
  131. package/src/core/dto/bot-detector.dto.ts +32 -0
  132. package/src/core/dto/device-detector.dto.ts +67 -0
  133. package/src/core/dto/fingerprint.dto.ts +38 -0
  134. package/src/core/dto/ginger.dto.ts +89 -0
  135. package/src/core/dto/incognito-detector.dto.ts +2 -0
  136. package/src/core/dto/index.ts +18 -0
  137. package/src/core/dto/metrics.dto.ts +20 -0
  138. package/src/core/dto/os-detector.dto.ts +5 -0
  139. package/src/core/dto/tor-detector.dto.ts +4 -0
  140. package/src/core/helpers.ts +33 -0
  141. package/src/core/http/httpClient.ts +52 -0
  142. package/src/core/http/request.ts +32 -0
  143. package/src/core/index.ts +5 -0
  144. package/src/core/util/error.ts +40 -0
  145. package/src/core/util/generate-requestid.ts +63 -0
  146. package/src/device/components/audio/audio.ts +58 -0
  147. package/src/device/components/canvas/canvas.ts +88 -0
  148. package/src/device/components/extra/extra.ts +581 -0
  149. package/src/device/components/fonts/fonts.ts +143 -0
  150. package/src/device/components/hardware/hardware.ts +66 -0
  151. package/src/device/components/index.ts +14 -0
  152. package/src/device/components/locales/locales.ts +21 -0
  153. package/src/device/components/math/math.ts +39 -0
  154. package/src/device/components/permissions/permissions.ts +60 -0
  155. package/src/device/components/plugins/plugins.ts +22 -0
  156. package/src/device/components/screen/screen.ts +13 -0
  157. package/src/device/components/screen/screenResolution.ts +45 -0
  158. package/src/device/components/system/browser.ts +838 -0
  159. package/src/device/components/system/emoji.ts +134 -0
  160. package/src/device/components/system/system.ts +76 -0
  161. package/src/device/components/webgl/imageHash.ts +144 -0
  162. package/src/device/components/webgl/webgl.ts +302 -0
  163. package/src/device/factory.ts +54 -0
  164. package/src/device/index.ts +60 -0
  165. package/src/device/modules/bot.ts +25 -0
  166. package/src/device/modules/browserDetails.ts +11 -0
  167. package/src/device/modules/device/analyze-data.ts +150 -0
  168. package/src/device/modules/device/gather-data.ts +92 -0
  169. package/src/device/modules/device/helpers.ts +123 -0
  170. package/src/device/modules/device/index.ts +64 -0
  171. package/src/device/modules/fp.ts +138 -0
  172. package/src/device/modules/incognito.ts +253 -0
  173. package/src/device/modules/options.ts +17 -0
  174. package/src/device/modules/os.ts +15 -0
  175. package/src/device/modules/tor.ts +41 -0
  176. package/src/device/utils/async.ts +106 -0
  177. package/src/device/utils/browser_.ts +347 -0
  178. package/src/device/utils/commonPixels.ts +38 -0
  179. package/src/device/utils/data.ts +161 -0
  180. package/src/device/utils/dom.ts +148 -0
  181. package/src/device/utils/ephemeralIFrame.ts +35 -0
  182. package/src/device/utils/getMostFrequent.ts +39 -0
  183. package/src/device/utils/hash.ts +202 -0
  184. package/src/device/utils/misc.ts +18 -0
  185. package/src/device/utils/raceAll.ts +19 -0
  186. package/src/index.ts +3 -0
@@ -0,0 +1,138 @@
1
+ import {
2
+ FingerprintComponentValue,
3
+ GingerJsFp,
4
+ } from "../../core";
5
+ import {
6
+ componentInterface,
7
+ getComponentPromises,
8
+ timeoutInstance,
9
+ } from "../factory";
10
+ import { hash } from "../utils/hash";
11
+ import { raceAll } from "../utils/raceAll";
12
+ import { options } from "./options";
13
+
14
+ export async function getFingerprintData(): Promise<componentInterface> {
15
+ try {
16
+ const promiseMap: Record<
17
+ string,
18
+ Promise<componentInterface>
19
+ > = getComponentPromises();
20
+
21
+ const keys: string[] = Object.keys(promiseMap);
22
+ const promises: Promise<componentInterface>[] = Object.values(promiseMap);
23
+ const resolvedValues: (componentInterface | undefined)[] = await raceAll(
24
+ promises,
25
+ options?.timeout || 1000,
26
+ timeoutInstance
27
+ );
28
+
29
+ const resolvedComponents: Record<string, componentInterface> = {};
30
+
31
+ resolvedValues.forEach((value, index) => {
32
+ if (value !== undefined) {
33
+ resolvedComponents[keys[index]] = value;
34
+ }
35
+ });
36
+
37
+ return filterFingerprintData(
38
+ resolvedComponents,
39
+ options.exclude || [],
40
+ options.include || [],
41
+ ""
42
+ );
43
+ } catch (error) {
44
+ throw error;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * This function filters the fingerprint data based on the exclude and include list
50
+ * @param {componentInterface} obj - components objects from main componentInterface
51
+ * @param {string[]} excludeList - elements to exclude from components objects (e.g : 'canvas', 'system.browser')
52
+ * @param {string[]} includeList - elements to only include from components objects (e.g : 'canvas', 'system.browser')
53
+ * @param {string} path - auto-increment path iterating on key objects from components objects
54
+ * @returns {componentInterface} result - returns the final object before hashing in order to get fingerprint
55
+ */
56
+ export function filterFingerprintData(
57
+ obj: componentInterface,
58
+ excludeList: string[],
59
+ includeList: string[],
60
+ path: string = ""
61
+ ): componentInterface {
62
+ const result: componentInterface = {};
63
+ for (const [key, value] of Object.entries(obj)) {
64
+ const currentPath = path + key + ".";
65
+
66
+ if (typeof value === "object" && !Array.isArray(value)) {
67
+ const filtered = filterFingerprintData(
68
+ value,
69
+ excludeList,
70
+ includeList,
71
+ currentPath
72
+ );
73
+ if (Object.keys(filtered).length > 0) {
74
+ result[key] = filtered;
75
+ }
76
+ } else {
77
+ const isExcluded = excludeList.some((exclusion) =>
78
+ currentPath.startsWith(exclusion)
79
+ );
80
+ const isIncluded = includeList.some((inclusion) =>
81
+ currentPath.startsWith(inclusion)
82
+ );
83
+
84
+ if (!isExcluded || isIncluded) {
85
+ result[key] = value;
86
+ }
87
+ }
88
+ }
89
+
90
+ return result;
91
+ }
92
+
93
+ export async function getFingerprint(): Promise<GingerJsFp> {
94
+ try {
95
+ const fingerprintData = await getFingerprintData();
96
+
97
+ const serializedFingerprint = getSerializedFingerprintObj(fingerprintData);
98
+ const thisHash = hash(JSON.stringify(serializedFingerprint));
99
+ const componentsUsedForHash = getHashRelevantKeys(serializedFingerprint as componentInterface);
100
+ return {
101
+ hash: thisHash.toString(),
102
+ data: fingerprintData,
103
+ componentsUsedForHash: componentsUsedForHash,
104
+ };
105
+ } catch (error) {
106
+ throw error;
107
+ }
108
+ }
109
+
110
+ function serializedObject(data: componentInterface): FingerprintComponentValue {
111
+ return {
112
+ audio: data.audio,
113
+ fonts: data.fonts,
114
+ hardware: data.hardware,
115
+ math: data.math,
116
+ permissions: data.permissions,
117
+ screen: data.screen,
118
+ system: data.system,
119
+ emojiFingerprint: data.emojiFingerprint,
120
+ vendorFlavour: data.vendorFlavour,
121
+ colorGamut: data.colorGamut,
122
+ canvas: data.canvas,
123
+ webglBasics: data.webGlBasics,
124
+ };
125
+ }
126
+
127
+ function getSerializedFingerprintObj(
128
+ data: componentInterface
129
+ ): FingerprintComponentValue {
130
+ return serializedObject(data);
131
+ }
132
+
133
+ function getHashRelevantKeys(
134
+ data: componentInterface
135
+ ): Array<keyof FingerprintComponentValue> {
136
+ const fpdata = serializedObject(data);
137
+ return Object.keys(fpdata) as Array<keyof FingerprintComponentValue>;
138
+ }
@@ -0,0 +1,253 @@
1
+ type IncognitoDetectionResult = {
2
+ status: boolean;
3
+ browser_name: string;
4
+ };
5
+
6
+ async function detectIncognito(): Promise<IncognitoDetectionResult> {
7
+ return new Promise(function (resolve, reject) {
8
+ let browser_name = 'unknown';
9
+
10
+ function __callback (status: boolean): void {
11
+ resolve({
12
+ status,
13
+ browser_name
14
+ })
15
+ }
16
+
17
+ function identifyChromium (): string {
18
+ const ua = navigator.userAgent
19
+ if (ua.match(/Chrome/)) {
20
+ if ((navigator as any).brave !== undefined) {
21
+ return 'Brave'
22
+ } else if (ua.match(/Edg/)) {
23
+ return 'Edge'
24
+ } else if (ua.match(/OPR/)) {
25
+ return 'Opera'
26
+ }
27
+ return 'Chrome'
28
+ } else {
29
+ return 'Chromium'
30
+ }
31
+ }
32
+
33
+ function assertEvalToString (value: number): boolean {
34
+ return value === eval.toString().length
35
+ }
36
+
37
+ function feid (): number {
38
+ let toFixedEngineID = 0
39
+ let neg = parseInt("-1")
40
+ try {
41
+ neg.toFixed(neg)
42
+ } catch (e) {
43
+ toFixedEngineID = (e as Error).message.length
44
+ }
45
+ return toFixedEngineID
46
+ }
47
+
48
+ function isSafari (): boolean {
49
+ return feid() === 44
50
+ }
51
+
52
+ function isChrome (): boolean {
53
+ return feid() === 51
54
+ }
55
+
56
+ function isFirefox (): boolean {
57
+ return feid() === 25
58
+ }
59
+
60
+ function isMSIE (): boolean {
61
+ return (
62
+ (navigator as any).msSaveBlob !== undefined && assertEvalToString(39)
63
+ )
64
+ }
65
+
66
+ /**
67
+ * Safari (Safari for iOS & macOS)
68
+ **/
69
+
70
+ function newSafariTestByStorageFallback (): void {
71
+ if (!navigator.storage?.estimate) {
72
+ __callback(false);
73
+ return;
74
+ }
75
+
76
+ navigator.storage
77
+ .estimate()
78
+ .then(({ quota }) => {
79
+ // iOS 18.x/macOS Safari 18.x (normal): ~41GB
80
+ // iOS 18.x/macOS Safari 18.x (private): ~1GB
81
+ // If reported quota < 2 GB => likely private
82
+ if (quota && quota < 2_000_000_000) {
83
+ __callback(true);
84
+ } else {
85
+ __callback(false);
86
+ }
87
+ })
88
+ .catch(() => {
89
+ __callback(false);
90
+ });
91
+ }
92
+
93
+ function newSafariTest (): void {
94
+ const tmp_name = String(Math.random())
95
+
96
+ try {
97
+ const db = window.indexedDB.open(tmp_name, 1)
98
+
99
+ db.onupgradeneeded = function (i: any) {
100
+ const res = i.target?.result
101
+
102
+ try {
103
+ res.createObjectStore('test', {
104
+ autoIncrement: true
105
+ }).put(new Blob())
106
+ } catch (e) {
107
+ let message = e
108
+
109
+ if (e instanceof Error) {
110
+ message = e.message ?? e
111
+ }
112
+
113
+ if (typeof message !== 'string') {
114
+ __callback(false); return
115
+ }
116
+
117
+ const matchesExpectedError = message.includes('BlobURLs are not yet supported')
118
+ if (matchesExpectedError) {
119
+ __callback(true)
120
+ }
121
+ } finally {
122
+ res.close()
123
+ window.indexedDB.deleteDatabase(tmp_name)
124
+
125
+ // indexdb works on newer versions of safari so we need to check via storage fallback
126
+ newSafariTestByStorageFallback();
127
+ }
128
+ }
129
+ } catch (e) {
130
+ __callback(false)
131
+ }
132
+ }
133
+
134
+ function oldSafariTest (): void {
135
+ const openDB = (window as any).openDatabase
136
+ const storage = window.localStorage
137
+ try {
138
+ openDB(null, null, null, null)
139
+ } catch (e) {
140
+ __callback(true); return
141
+ }
142
+ try {
143
+ storage.setItem('test', '1')
144
+ storage.removeItem('test')
145
+ } catch (e) {
146
+ __callback(true); return
147
+ }
148
+ __callback(false)
149
+ }
150
+
151
+ function safariPrivateTest (): void {
152
+ if (navigator.maxTouchPoints !== undefined) {
153
+ newSafariTest()
154
+ } else {
155
+ oldSafariTest()
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Chrome
161
+ **/
162
+
163
+ function getQuotaLimit (): number {
164
+ const w = window as any
165
+ if (
166
+ w.performance !== undefined &&
167
+ w.performance.memory !== undefined &&
168
+ w.performance.memory.jsHeapSizeLimit !== undefined
169
+ ) {
170
+ return (performance as any).memory.jsHeapSizeLimit
171
+ }
172
+ return 1073741824
173
+ }
174
+
175
+ // >= 76
176
+ function storageQuotaChromePrivateTest (): void {
177
+ (navigator as any).webkitTemporaryStorage.queryUsageAndQuota(
178
+ function (_: number, quota: number) {
179
+ const quotaInMib = Math.round(quota / (1024 * 1024))
180
+ const quotaLimitInMib = Math.round(getQuotaLimit() / (1024 * 1024)) * 2
181
+
182
+ __callback(quotaInMib < quotaLimitInMib)
183
+ },
184
+ function (e: any) {
185
+ reject(
186
+ new Error(
187
+ 'detectIncognito somehow failed to query storage quota: ' +
188
+ e.message
189
+ )
190
+ )
191
+ }
192
+ )
193
+ }
194
+
195
+ // 50 to 75
196
+ function oldChromePrivateTest (): void {
197
+ const fs = (window as any).webkitRequestFileSystem
198
+ const success = function () {
199
+ __callback(false)
200
+ }
201
+ const error = function () {
202
+ __callback(true)
203
+ }
204
+ fs(0, 1, success, error)
205
+ }
206
+
207
+ function chromePrivateTest (): void {
208
+ if (self.Promise !== undefined && (self.Promise as any).allSettled !== undefined) {
209
+ storageQuotaChromePrivateTest()
210
+ } else {
211
+ oldChromePrivateTest()
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Firefox
217
+ **/
218
+
219
+ function firefoxPrivateTest (): void {
220
+ __callback(navigator.serviceWorker === undefined)
221
+ }
222
+
223
+ /**
224
+ * MSIE
225
+ **/
226
+
227
+ function msiePrivateTest (): void {
228
+ __callback(window.indexedDB === undefined)
229
+ }
230
+
231
+ function main (): void {
232
+ if (isSafari()) {
233
+ browser_name = 'Safari'
234
+ safariPrivateTest()
235
+ } else if (isChrome()) {
236
+ browser_name = identifyChromium()
237
+ chromePrivateTest()
238
+ } else if (isFirefox()) {
239
+ browser_name = 'Firefox'
240
+ firefoxPrivateTest()
241
+ } else if (isMSIE()) {
242
+ browser_name = 'Internet Explorer'
243
+ msiePrivateTest()
244
+ } else {
245
+ reject(new Error('detectIncognito cannot determine the browser'))
246
+ }
247
+ }
248
+
249
+ main()
250
+ })
251
+ }
252
+
253
+ export {detectIncognito}
@@ -0,0 +1,17 @@
1
+ export interface optionsInterface {
2
+ exclude: string[],
3
+ include: string[],
4
+ webgl_runs?: number,
5
+ canvas_runs?: number,
6
+ permissions_to_check?: PermissionName[], // new option
7
+ retries?: number, // new option
8
+ timeout?: number, // new option
9
+ logging: boolean
10
+ }
11
+
12
+ export let options: optionsInterface = {
13
+ exclude: [],
14
+ include: [],
15
+ logging: true,
16
+ }
17
+
@@ -0,0 +1,15 @@
1
+ import { UAParser } from "ua-parser-js";
2
+ import { DeviceOs } from "../../core";
3
+
4
+ export const getOs = async (): Promise<DeviceOs> => {
5
+ const parser = new UAParser(navigator.userAgent);
6
+ const result = parser.getResult();
7
+ return { ...result.os, device_type: getDeviceType() };
8
+ };
9
+
10
+ const getDeviceType = () => {
11
+ const w = window.innerWidth;
12
+ if (w <= 767) return 'mobile';
13
+ if (w <= 1024) return 'tablet';
14
+ return 'desktop';
15
+ };
@@ -0,0 +1,41 @@
1
+ import { TorDetectionResult } from "../../core";
2
+
3
+ async function detectTorBrowser(): Promise<TorDetectionResult> {
4
+ const totalChecks = 7;
5
+ let score = 0;
6
+
7
+ const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
8
+ if (tz === "Atlantic/Reykjavik") score++;
9
+ const webGLInfo = getWebGLInfo();
10
+ if (["Mozilla", "unknown"].includes(webGLInfo.vendor)) score++;
11
+ if (!window.RTCPeerConnection) score++;
12
+ if (!(navigator as any).deviceMemory) score++;
13
+ if (navigator.hardwareConcurrency === 2) score++;
14
+ if (!navigator.credentials) score++;
15
+ if (!navigator.geolocation) score++;
16
+
17
+ return {
18
+ status: score >= 6,
19
+ confidence: `${((score / totalChecks)).toFixed(2)}`,
20
+ };
21
+ }
22
+
23
+ const getWebGLInfo = (): { vendor: string; renderer: string } => {
24
+ try {
25
+ const canvas = document.createElement("canvas");
26
+ const gl: any =
27
+ canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
28
+ if (!gl) return { vendor: "unsupported", renderer: "unsupported" };
29
+ const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
30
+ return debugInfo
31
+ ? {
32
+ vendor: gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL),
33
+ renderer: gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL),
34
+ }
35
+ : { vendor: "unknown", renderer: "unknown" };
36
+ } catch {
37
+ return { vendor: "error", renderer: "error" };
38
+ }
39
+ };
40
+
41
+ export { detectTorBrowser };
@@ -0,0 +1,106 @@
1
+ export type MaybePromise<T> = Promise<T> | T
2
+
3
+ export function wait<T = void>(durationMs: number, resolveWith?: T): Promise<T> {
4
+ return new Promise((resolve) => setTimeout(resolve, durationMs, resolveWith))
5
+ }
6
+
7
+ /**
8
+ * Allows asynchronous actions and microtasks to happen.
9
+ */
10
+ function releaseEventLoop(): Promise<void> {
11
+ // Don't use setTimeout because Chrome throttles it in some cases causing very long agent execution:
12
+ // https://stackoverflow.com/a/6032591/1118709
13
+ // https://github.com/chromium/chromium/commit/0295dd09496330f3a9103ef7e543fa9b6050409b
14
+ // Reusing a MessageChannel object gives no noticeable benefits
15
+ return new Promise((resolve) => {
16
+ const channel = new MessageChannel()
17
+ channel.port1.onmessage = () => resolve()
18
+ channel.port2.postMessage(null)
19
+ })
20
+ }
21
+
22
+ export function requestIdleCallbackIfAvailable(fallbackTimeout: number, deadlineTimeout = Infinity): Promise<void> {
23
+ const { requestIdleCallback } = window
24
+ if (requestIdleCallback) {
25
+ // The function `requestIdleCallback` loses the binding to `window` here.
26
+ // `globalThis` isn't always equal `window` (see https://github.com/fingerprintjs/fingerprintjs/issues/683).
27
+ // Therefore, an error can occur. `call(window,` prevents the error.
28
+ return new Promise((resolve) => requestIdleCallback.call(window, () => resolve(), { timeout: deadlineTimeout }))
29
+ } else {
30
+ return wait(Math.min(fallbackTimeout, deadlineTimeout))
31
+ }
32
+ }
33
+
34
+ export function isPromise<T>(value: PromiseLike<T> | unknown): value is PromiseLike<T> {
35
+ return !!value && typeof (value as PromiseLike<T>).then === 'function'
36
+ }
37
+
38
+ /**
39
+ * Calls a maybe asynchronous function without creating microtasks when the function is synchronous.
40
+ * Catches errors in both cases.
41
+ *
42
+ * If just you run a code like this:
43
+ * ```
44
+ * console.time('Action duration')
45
+ * await action()
46
+ * console.timeEnd('Action duration')
47
+ * ```
48
+ * The synchronous function time can be measured incorrectly because another microtask may run before the `await`
49
+ * returns the control back to the code.
50
+ */
51
+ export function awaitIfAsync<TResult, TError = unknown>(
52
+ action: () => MaybePromise<TResult>,
53
+ callback: (...args: [success: true, result: TResult] | [success: false, error: TError]) => unknown,
54
+ ): void {
55
+ try {
56
+ const returnedValue = action()
57
+ if (isPromise(returnedValue)) {
58
+ returnedValue.then(
59
+ (result) => callback(true, result),
60
+ (error: TError) => callback(false, error),
61
+ )
62
+ } else {
63
+ callback(true, returnedValue)
64
+ }
65
+ } catch (error) {
66
+ callback(false, error as TError)
67
+ }
68
+ }
69
+
70
+ /**
71
+ * If you run many synchronous tasks without using this function, the JS main loop will be busy and asynchronous tasks
72
+ * (e.g. completing a network request, rendering the page) won't be able to happen.
73
+ * This function allows running many synchronous tasks such way that asynchronous tasks can run too in background.
74
+ */
75
+ export async function mapWithBreaks<T, U>(
76
+ items: readonly T[],
77
+ callback: (item: T, index: number) => U,
78
+ loopReleaseInterval = 16,
79
+ ): Promise<U[]> {
80
+ const results = Array<U>(items.length)
81
+ let lastLoopReleaseTime = Date.now()
82
+
83
+ for (let i = 0; i < items.length; ++i) {
84
+ results[i] = callback(items[i], i)
85
+
86
+ const now = Date.now()
87
+ if (now >= lastLoopReleaseTime + loopReleaseInterval) {
88
+ lastLoopReleaseTime = now
89
+ await releaseEventLoop()
90
+ }
91
+ }
92
+
93
+ return results
94
+ }
95
+
96
+ /**
97
+ * Makes the given promise never emit an unhandled promise rejection console warning.
98
+ * The promise will still pass errors to the next promises.
99
+ * Returns the input promise for convenience.
100
+ *
101
+ * Otherwise, promise emits a console warning unless it has a `catch` listener.
102
+ */
103
+ export function suppressUnhandledRejectionWarning<T extends PromiseLike<unknown>>(promise: T): T {
104
+ promise.then(undefined, () => undefined)
105
+ return promise
106
+ }