File size: 7,736 Bytes
6bc074c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package browserfp

import (
	"math/rand"
	"strings"
	"time"
)

// โ”€โ”€โ”€ Language โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

// Language ๆต่งˆๅ™จ่ฏญ่จ€ๆก็›ฎใ€‚
type Language struct {
	Code     string // "en-US"
	JoinList string // "en-US,en"
}

// Slice ่ฟ”ๅ›ž [][]string ็š„ []string ๅฝขๅผใ€‚
func (l Language) Slice() []string { return strings.Split(l.JoinList, ",") }

// LanguageJoin ่ฟ”ๅ›ž code ๅฏนๅบ”็š„ languagesJoin ๅญ—็ฌฆไธฒใ€‚
func LanguageJoin(code string) string {
	for _, l := range Languages {
		if l.Code == code {
			return l.JoinList
		}
	}
	return code + ",en"
}

// LanguageSlices ๆ‰€ๆœ‰ Language ็š„ [][]string ๅฝขๅผใ€‚
func LanguageSlices() [][]string {
	out := make([][]string, len(Languages))
	for i, l := range Languages {
		out[i] = l.Slice()
	}
	return out
}

// โ”€โ”€โ”€ ้€š็”จๆ•ฐๆฎๆฑ  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

// UserAgents ็œŸๅฎž Chrome UA ๆฑ ใ€‚
var UserAgents = []string{
	"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
	"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36",
	"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
	"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
	"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36",
}

// Languages ๆต่งˆๅ™จ navigator.languages ็ป„ๅˆใ€‚
var Languages = []Language{
	{"en-US", "en-US,en"},
	{"zh-CN", "zh-CN,zh"},
	{"en-GB", "en-GB,en"},
	{"ja", "ja,en"},
	{"de", "de,en"},
	{"fr", "fr,en"},
	{"es", "es,en"},
	{"ko", "ko,en"},
}

// Platforms ๆต่งˆๅ™จ navigator.platform ๅ€ผใ€‚
var Platforms = []string{"Win32", "Win32", "MacIntel", "Linux x86_64", "Linux armv8l", "Linux i686"}

// DocumentKeys document ไธŠ own-enumerable ๅฑžๆ€งๅๆฑ ใ€‚
var DocumentKeys = []string{
	"_reactListening8in7sfyhjvp", "_reactListeningo743lnnpvdg",
	"_reactContainer$5pyziap1brc", "__reactContainer$b63yiita51i",
	"location", "cookie", "referrer", "currentScript", "body", "head", "documentElement",
}

// WindowKeys window ๅ…จๅฑ€ๅฑžๆ€งๅๆฑ ใ€‚
var WindowKeys = []string{
	"onchange", "onclick", "onload", "onerror", "onresize",
	"onmouseover", "onmouseout", "onfocus", "onblur", "onscroll",
	"onkeydown", "onkeyup", "onkeypress",
	"requestIdleCallback", "requestAnimationFrame", "setTimeout",
	"fetch", "console", "Promise", "Map", "Set", "WeakMap", "WeakSet",
	"crypto", "performance", "navigator", "document", "location", "history",
	"localStorage", "sessionStorage", "indexedDB",
	"Image", "XMLHttpRequest", "FormData", "Headers", "Request", "Response",
	"alert", "confirm", "prompt", "close", "focus", "blur",
	"addEventListener", "removeEventListener", "dispatchEvent",
	"scrollTo", "scrollBy", "scroll", "matchMedia", "getComputedStyle",
	"getSelection", "find", "stop", "open", "print", "captureEvents",
	"releaseEvents", "queueMicrotask", "reportError", "structuredClone",
	"isSecureContext", "crossOriginIsolated", "originAgentCluster",
	"speechSynthesis", "MediaSource", "Blob", "File", "FileReader",
	"Atomics", "SharedArrayBuffer", "WebAssembly", "BigInt", "Symbol", "Proxy",
}

// NavigatorProbes "X in navigator" ๆŽขๆต‹ๆ ผๅผใ€‚
var NavigatorProbes = []string{
	"windowControlsOverlayโˆ’[object WindowControlsOverlay]",
	"geolocationโˆ’[object Geolocation]",
	"clipboardโˆ’[object Clipboard]",
	"mediaDevicesโˆ’[object MediaDevices]",
	"permissionsโˆ’[object Permissions]",
	"bluetoothโˆ’[object Bluetooth]",
	"usbโˆ’[object USB]",
	"serialโˆ’[object Serial]",
	"hidโˆ’[object HID]",
	"presentationโˆ’[object Presentation]",
	"credentialsโˆ’[object CredentialsContainer]",
}

// ScriptURLs sentinel SDK ่„šๆœฌ URL ๆฑ ใ€‚
// ๆต่งˆๅ™จไธญ hPt(Array.from(document.scripts).map(e=>e?.src).filter(e=>e))
// ไผš้šๆœบ้€‰ไธ€ไธช script URLใ€‚
var ScriptURLs = []string{
	"https://chatgpt.com/backend-api/sentinel/sdk.js",
	"https://chatgpt.com/sentinel/20260423af3c/sdk.js",
}

// DefaultBuildID ๅฝ“ๅ‰ chatgpt.com ็š„ data-build ๅฑžๆ€งใ€‚
const DefaultBuildID = "prod-dbbd612ddb47498515c3eecf8579bcafa0066e07"

// VendorForPlatform ่ฟ”ๅ›ž็ป™ๅฎšๅนณๅฐ็š„ navigator.vendor ๅ€ผใ€‚
func VendorForPlatform(platform string) string {
	if platform == "MacIntel" {
		return "Apple Computer, Inc."
	}
	return "Google Inc."
}

// โ”€โ”€โ”€ Profile โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

// Profile ๆต่งˆๅ™จๆŒ‡็บน้…็ฝฎใ€‚
type Profile struct {
	WebGLUnmaskedRenderer string
	WebGLUnmaskedVendor   string
	Language              string
	BuildID               string
	Platform              string
	ScreenWidth           int
	ScreenHeight          int
	ScreenAvailHeight     int
	ScreenColorDepth      int
	HardwareConcurrency   int
	DeviceMemory          int
	JSHeapSizeLimit       int64
	NetworkDownlink       float64
	NetworkRTT            int
	TimezoneOffset        int
	DevicePixelRatio      float64
}

// โ”€โ”€โ”€ ๅ…จๅฑ€ๅ•ไพ‹ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

var current *Profile

// Init ๅฏๅŠจๆ—ถ่ฐƒ็”จไธ€ๆฌก๏ผŒ็”Ÿๆˆๅ…จๅฑ€ๅ”ฏไธ€็š„ Profileใ€‚
func Init() { current = Generate(nil) }

// Get ่ฟ”ๅ›žๅ…จๅฑ€ๅ”ฏไธ€็š„ Profileใ€‚
func Get() *Profile { return current }

// Generate ไปŽ็œŸๅฎžๆ•ฐๆฎๆฑ ไธญ้šๆœบ็”Ÿๆˆ Profileใ€‚
func Generate(rng *rand.Rand) *Profile {
	if rng == nil {
		rng = rand.New(rand.NewSource(time.Now().UnixNano()))
	}

	lang := Languages[rng.Intn(len(Languages))]
	platform := Platforms[rng.Intn(len(Platforms))]
	sr := screenResolutions[rng.Intn(len(screenResolutions))]
	sw, sh := sr[0]+rng.Intn(101)-50, sr[1]+rng.Intn(101)-50
	if sw < 1024 {
		sw = 1024
	}
	if sh < 600 {
		sh = 600
	}

	vendorIdx := rng.Intn(len(webglUnmaskedVendors))

	return &Profile{
		WebGLUnmaskedVendor:   webglUnmaskedVendors[vendorIdx],
		WebGLUnmaskedRenderer: webglUnmaskedRenderersMap[vendorIdx][rng.Intn(len(webglUnmaskedRenderersMap[vendorIdx]))],

		Language: lang.Code,
		BuildID:  DefaultBuildID,
		Platform: platform,

		ScreenWidth:       sw,
		ScreenHeight:      sh,
		ScreenAvailHeight: sh - (20 + rng.Intn(40)),
		ScreenColorDepth:  24,

		HardwareConcurrency: pickInt(rng, []int{4, 8, 12, 16, 20, 24, 32}),
		DeviceMemory:        pickInt(rng, []int{4, 8, 16, 32}),
		JSHeapSizeLimit:     pickInt64(rng, []int64{2_147_483_648, 4_294_967_296, 8_589_934_592, 17_179_869_184}),

		NetworkDownlink: networkDownlinks[rng.Intn(len(networkDownlinks))],
		NetworkRTT:      networkRTTs[rng.Intn(len(networkRTTs))],

			DevicePixelRatio: devicePixelRatios[rng.Intn(len(devicePixelRatios))],

		TimezoneOffset: (rng.Intn(23) - 12) * 60,
	}
}

// โ”€โ”€โ”€ ๅ†…้ƒจ่พ…ๅŠฉ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

func pickStr(rng *rand.Rand, opts []string) string { return opts[rng.Intn(len(opts))] }
func pickInt(rng *rand.Rand, opts []int) int        { return opts[rng.Intn(len(opts))] }
func pickInt64(rng *rand.Rand, opts []int64) int64  { return opts[rng.Intn(len(opts))] }