fingerprintjs
168 строк · 4.8 Кб
1import * as FingerprintJS from '../src'
2import { errorToObject } from '../src/utils/misc'
3
4type Text = string | { html: string }
5
6async function getVisitorData() {
7const fp = await FingerprintJS.load({ debug: true })
8return await fp.get()
9}
10
11async function startPlayground() {
12const output = document.querySelector('.output')
13if (!output) {
14throw new Error("The output element isn't found in the HTML code")
15}
16
17const startTime = Date.now()
18
19try {
20const { visitorId, confidence, components } = await getVisitorData()
21const totalTime = Date.now() - startTime
22output.innerHTML = ''
23addOutputSection({ output, header: 'Visitor identifier:', content: visitorId, size: 'giant' })
24addOutputSection({ output, header: 'Time took to get the identifier:', content: `${totalTime}ms`, size: 'big' })
25addOutputSection({
26output,
27header: 'Confidence score:',
28content: String(confidence.score),
29comment: confidence.comment && {
30html: confidence.comment.replace(
31/(upgrade\s+to\s+)?pro(\s+version)?(:\s+(https?:\/\/\S+))?/gi,
32'<a href="$4" target="_blank">$&</a>',
33),
34},
35size: 'big',
36})
37addOutputSection({ output, header: 'User agent:', content: navigator.userAgent })
38addOutputSection({
39output,
40header: 'Entropy components:',
41content: FingerprintJS.componentsToDebugString(components),
42})
43
44initializeDebugButtons(`Visitor identifier: \`${visitorId}\`
45Time took to get the identifier: ${totalTime}ms
46Confidence: ${JSON.stringify(confidence)}
47User agent: \`${navigator.userAgent}\`
48Entropy components:
49\`\`\`
50${FingerprintJS.componentsToDebugString(components)}
51\`\`\``)
52} catch (error) {
53const totalTime = Date.now() - startTime
54const errorData = error instanceof Error ? errorToObject(error) : error
55output.innerHTML = ''
56addOutputSection({ output, header: 'Unexpected error:', content: JSON.stringify(errorData, null, 2) })
57addOutputSection({ output, header: 'Time passed before the error:', content: `${totalTime}ms`, size: 'big' })
58addOutputSection({ output, header: 'User agent:', content: navigator.userAgent })
59
60initializeDebugButtons(`Unexpected error:\n
61\`\`\`
62${JSON.stringify(errorData, null, 2)}
63\`\`\`
64Time passed before the error: ${totalTime}ms
65User agent: \`${navigator.userAgent}\``)
66throw error
67}
68}
69
70function addOutputSection({
71output,
72header,
73content,
74comment,
75size,
76}: {
77output: Node
78header: Text
79content: Text
80comment?: Text
81size?: 'big' | 'giant'
82}) {
83const headerElement = document.createElement('div')
84headerElement.appendChild(textToDOM(header))
85headerElement.classList.add('heading')
86output.appendChild(headerElement)
87
88const contentElement = document.createElement('pre')
89contentElement.appendChild(textToDOM(content))
90if (size) {
91contentElement.classList.add(size)
92}
93output.appendChild(contentElement)
94
95if (comment) {
96const commentElement = document.createElement('div')
97commentElement.appendChild(textToDOM(comment))
98commentElement.classList.add('comment')
99output.appendChild(commentElement)
100}
101}
102
103function initializeDebugButtons(debugText: string) {
104const copyButton = document.querySelector('#debugCopy')
105if (copyButton instanceof HTMLButtonElement) {
106copyButton.disabled = false
107copyButton.addEventListener('click', (event) => {
108event.preventDefault()
109copy(debugText)
110})
111}
112
113const shareButton = document.querySelector('#debugShare')
114if (shareButton instanceof HTMLButtonElement) {
115shareButton.disabled = false
116shareButton.addEventListener('click', (event) => {
117event.preventDefault()
118share(debugText)
119})
120}
121}
122
123function copy(text: string) {
124const textarea = document.createElement('textarea')
125textarea.value = text
126document.body.appendChild(textarea)
127textarea.focus()
128textarea.select()
129try {
130document.execCommand('copy')
131} catch {
132// Do nothing in case of a copying error
133}
134document.body.removeChild(textarea)
135}
136
137async function share(text: string) {
138if (!navigator.share) {
139alert(`Sharing is unavailable.
140
141Sharing is available in mobile browsers and only on HTTPS websites. ${
142location.protocol === 'https:'
143? 'Use a mobile device or the Copy button instead.'
144: `Open https://${location.host}${location.pathname}${location.search} instead.`
145}`)
146return
147}
148try {
149await navigator.share({ text })
150} catch {
151// Do nothing in case of a share abort
152}
153}
154
155function textToDOM(text: Text): Node {
156if (typeof text === 'string') {
157return document.createTextNode(text)
158}
159const container = document.createElement('div')
160container.innerHTML = text.html
161const fragment = document.createDocumentFragment()
162while (container.firstChild) {
163fragment.appendChild(container.firstChild)
164}
165return fragment
166}
167
168startPlayground()
169