@tocha688/browser 1.0.2 → 1.0.4

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.
@@ -1,245 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { faker } from "@faker-js/faker";
4
- import { adsEncodeBase64, adsDecodeBase64 } from "./ads_tool";
5
- import { PcScreen, WindowsWebGL, Cpus, Memorys, rSysFonts } from "../const/browser";
6
- import type { BrowserResult, BrowserStartOptions } from "../types";
7
- import { checkAutoProxy, rArrItem, rInt, uuidV4, rAutoDigitInt, type ProxyServerResult, startProxyServer, getIpInfo } from "@tocha688/utils";
8
- import { launchBrowserBase } from "./base";
9
-
10
- export async function AdsBrowserStartMain(opts: BrowserStartOptions): Promise<BrowserResult> {
11
- return launchBrowserBase(opts, {
12
- prepare: async (userDataDir, devtoolsPort) => {
13
-
14
- const webGLFP_path = path.join(userDataDir, "webgl.json")
15
- const dynamicConfig_path = path.join(userDataDir, "dynamic.config")
16
- const staticConfig_path = path.join(userDataDir, "static.config")
17
- const params_path = path.join(userDataDir, "params.config")
18
-
19
-
20
- let params: string;
21
- let screenSize: string;
22
-
23
- if (fs.existsSync(params_path)) {
24
- params = fs.readFileSync(params_path, "utf-8");
25
- const decoded = JSON.parse(adsDecodeBase64(params));
26
- screenSize = decoded.ScreenSize;
27
- } else {
28
- let ipinfo: any = {};
29
- let proxyInfo: URL | undefined;
30
-
31
- if (opts.proxy) {
32
- ipinfo = await checkAutoProxy(opts.proxy);
33
- proxyInfo = new URL(ipinfo.proxy)
34
- } else {
35
- ipinfo = await getIpInfo(ipinfo.proxy);
36
- }
37
- // console.log(ipinfo)
38
- // webgl指纹
39
- const config = {
40
- // 指纹随机数种子
41
- fp: rInt(100000, 999999),
42
- geop: ipinfo?.latitude ? ipinfo?.latitude + "," + ipinfo?.longitude : "",
43
- // 加上随机字符串 MSBYH29R
44
- device_name: "PC" + faker.string.alphanumeric(8).toUpperCase(),
45
- timezone: ipinfo?.timezone || ipinfo?.timeZone || "America/Los_Angeles",
46
- proxy: {
47
- protocol: proxyInfo?.protocol.replace(":", "") || "http",
48
- host: proxyInfo?.hostname || "127.0.0.1",
49
- port: proxyInfo?.port || "8080",
50
- username: proxyInfo?.username || "",
51
- password: proxyInfo?.password || "",
52
- },
53
- mac: faker.internet.mac(),
54
- scanPorts: "",
55
- screenSize: rArrItem(PcScreen),
56
- langs: ipinfo?.languages ?? "en-US,en",
57
- }
58
- // console.log(config)
59
- const webGL = rArrItem(WindowsWebGL);
60
- const webGLFP = {
61
- "UNMASKED_VENDOR_WEBGL": webGL.name,
62
- "UNMASKED_RENDERER_WEBGL": rArrItem(webGL.values),
63
- "GPUAdapterInfo": {
64
- "vendor": webGL.vendor,
65
- "architecture": "pascal"
66
- },
67
- "SUPPORTED_EXTENSIONS": [
68
- ]
69
- }
70
- // 黑名单 在名单上的不会修改指纹
71
- const dynamic = {
72
- "BlockList": {
73
- "Version": "1743148877",
74
- // 白名单域名
75
- "Domains": []
76
- },
77
- "StrongBlockList": {
78
- "Version": "3",
79
- "Domains": []
80
- },
81
- "TimeZone": config.timezone,
82
- "Geoposition": config.geop
83
- }
84
- // 静态配置
85
- const staticConfig = {
86
- // "CookiesExportPath": "C:\\.ADSPOWER_GLOBAL\\cache\\k186hhvu_hwvl6k\\sf_cookie.txt",
87
- "CookiesExportPath": "",
88
- "SecurePreferenceSync": true,
89
- // "PasswordExportPath": "C:\\.ADSPOWER_GLOBAL\\cache\\k186hhvu_hwvl6k\\e2776b7f6d0ee269e7a3d43987c7b103",
90
- "PasswordExportPath": "",
91
- // "PasswordImportPath": "C:\\.ADSPOWER_GLOBAL\\cache\\k186hhvu_hwvl6k\\6c13174a34c549425974d259f9589e45",
92
- "PasswordImportPath": "",
93
- "RestoreLastSession": true,
94
- // 黑名单页面的html base64编码
95
- "BlockPage": "NDA0",
96
- "FoceSafeBrowsing": true,
97
- "ExtensionSetting": [
98
- // {
99
- // "path": "C:\\Users\\Administrator\\AppData\\Roaming\\Electron\\cwd_global\\lib\\tab_assistant",
100
- // "pinned": 0,
101
- // "hide": true,
102
- // "version": "0.0.1",
103
- // "accessWeb": true
104
- // }
105
- ],
106
- // 不修改指纹的域名列表 net-a-porter.com,nike.com,fedex.com,thenorthface,bybit.com,adidas.com,mrporter.com,lululemon.com,sephora.com,biglietti.italotreno.it,target.com,tangerine.ca,ipdog.io,dhl.com,spotify.com,vinted.com,pingpongx.com,uber.com,wildberries.ru
107
- "DisCanvasUrl": "",
108
- "MaxTouchPoints": 0,
109
- "MediaDevices": [
110
- {
111
- "kind": "audioinput",
112
- "label": "Microphone Array (Realtek(R) Audio)"
113
- },
114
- {
115
- "kind": "videoinput",
116
- "label": "Integrated Camera (98da:3959)"
117
- },
118
- {
119
- "kind": "audiooutput",
120
- "label": "Speakers (Realtek(R) Audio)"
121
- }
122
- ],
123
- "AudioFp": rAutoDigitInt(980, config.fp),
124
- // "WebGLMark": rAutoDigitInt("5001", config.fp).toString(),
125
- // "WebGLMark": config.fp.toString(),
126
- "WebGLMark": "5001",
127
- "StartTime": Math.floor(Date.now() / 1000),
128
- "GeolocationSetting": "ask",
129
- "FlashPluginSetting": "block",
130
- "Platform": "Win32",
131
- "ScreenSize": config.screenSize,
132
- "DisableBackgroundMode": true,
133
- "DisableWebRTC": true,
134
- "HardwareConcurrency": rArrItem(Cpus),
135
- // "DeviceMemory": rArrItem(Memorys),
136
- "DeviceMemory": rArrItem([4, 8]),
137
- "LoadExtensionErrorBox": false,
138
- "ClientRectFp": rAutoDigitInt("5001", config.fp).toString(),
139
- "ForceProcessExit": true,
140
- "ProxyUser": config.proxy.username,
141
- "ProxyPassword": config.proxy.password,
142
- "Langs": config.langs,
143
- "AcceptLang": config.langs ? config.langs + ",q=0.9" : "en-US,en;q=0.9",
144
- // 禁用字体
145
- "DisabledFonts": (await rSysFonts()).join(","),
146
- }
147
-
148
- fs.writeFileSync(webGLFP_path, JSON.stringify(webGLFP))
149
- fs.writeFileSync(dynamicConfig_path, adsEncodeBase64(JSON.stringify(dynamic)))
150
- fs.writeFileSync(staticConfig_path, adsEncodeBase64(JSON.stringify(staticConfig)))
151
-
152
- params = adsEncodeBase64(JSON.stringify({
153
- "UserId": "1",
154
- "CanvasMark": rAutoDigitInt("7949", config.fp).toString(),
155
- "DisableContainer": true,
156
- "WebGLFP": webGLFP_path,
157
- "AudioFp": staticConfig.AudioFp,
158
- "WebGLMark": staticConfig.WebGLMark,
159
- "StartTime": staticConfig.StartTime,
160
- "AllowScanPorts": config.scanPorts,
161
- "GeolocationSetting": staticConfig.GeolocationSetting,
162
- "FlashPluginSetting": staticConfig.FlashPluginSetting,
163
- "Platform": staticConfig.Platform,
164
- "ScreenSize": staticConfig.ScreenSize,
165
- "DisableBackgroundMode": staticConfig.DisableBackgroundMode,
166
- "DisableWebRTC": staticConfig.DisableWebRTC,
167
- "HardwareConcurrency": staticConfig.HardwareConcurrency,
168
- "DeviceMemory": staticConfig.DeviceMemory,
169
- "LoadExtensionErrorBox": staticConfig.LoadExtensionErrorBox,
170
- "ClientRectFp": staticConfig.ClientRectFp,
171
- "CanvasMarkEx": rAutoDigitInt("7949", config.fp).toString(),
172
- "WebGLMarkEx": rAutoDigitInt("5001", config.fp).toString(),
173
- "command_line": {
174
- "do-not-de-elevate": ""
175
- },
176
- "ProxyChain": [
177
- {
178
- "scheme": config.proxy.protocol,
179
- "host": config.proxy.host,
180
- "port": config.proxy.port,
181
- "account": config.proxy.username,
182
- "password": config.proxy.password
183
- }
184
- ],
185
- "ForceProcessExit": staticConfig.ForceProcessExit,
186
- "ProxyUser": staticConfig.ProxyUser,
187
- "ProxyPassword": staticConfig.ProxyPassword,
188
- "Langs": staticConfig.Langs,
189
- "AcceptLang": staticConfig.AcceptLang,
190
- "TimeZone": config.timezone,
191
- "Geoposition": config.geop,
192
- "DynamicConfig": dynamicConfig_path,
193
- "StaticConfig": staticConfig_path
194
- }));
195
-
196
- fs.writeFileSync(params_path, params)
197
- screenSize = staticConfig.ScreenSize;
198
- }
199
-
200
-
201
- const args = [
202
- "--disable-background-networking",
203
- "--disable-client-side-phishing-detection",
204
- "--disable-default-apps",
205
- "--disable-hang-monitor",
206
- "--disable-popup-blocking",
207
- "--disable-prompt-on-repost",
208
- "--disable-sync",
209
- "--metrics-recording-only",
210
- "--no-first-run",
211
- "--safebrowsing-disable-auto-update",
212
- "--password-store=basic",
213
- "--no-service-autorun",
214
- "--disable-features=Translate,AcceptCHFrame,MediaRouter,OptimizationHints,ProcessPerSiteUpToMainFrameThreshold,IsolateSandboxedIframes",
215
- "--force-color-profile=srgb",
216
- "--use-mock-keychain",
217
- "--export-tagged-pdf",
218
- "--no-default-browser-check",
219
- "--window-position=0,0",
220
- "--disable-background-mode",
221
- "--ash-host-window-bounds=" + screenSize,
222
- "--window-size=" + screenSize,
223
- "--disable-renderer-accessibility",
224
- "--disable-legacy-window",
225
- "--fake-variations-channel=stable",
226
- "--variations-server-url=https://clientservices.googleapis.com/chrome-variations/seed",
227
- "--component-updater=initial-delay=6e5",
228
- "--lang=en-US",
229
- "--enable-features=NetworkService,NetworkServiceInProcess,LoadCryptoTokenExtension,PermuteTLSExtensions",
230
- "--enable-blink-features=IdleDetection,Fledge",
231
- "--extended-parameters=" + params,
232
- "--flag-switches-begin",
233
- "--flag-switches-end",
234
- "--load-extension=",
235
- // "--timezone=" + (ipinfo?.timezone ?? "America/Los_Angeles"),
236
- "--no-sandbox"
237
- ];
238
-
239
- return {
240
- args,
241
- startingUrl: "https://ipapi.co/json/"
242
- }
243
- }
244
- });
245
- }
@@ -1,80 +0,0 @@
1
- import { makeUniqueBrowserConfig, getBrowserWebSocketUrl } from "../core/launcher";
2
- import portfinder from 'portfinder';
3
- import fs from "fs";
4
- import * as cl from "chrome-launcher";
5
- import { getIpInfo, startProxyServer, tryCatch, tryLoop, type ProxyServerResult } from "@tocha688/utils";
6
- import type { BrowserResult, BrowserStartOptions } from "../types";
7
- import { chromium } from "patchright-core";
8
-
9
- export interface BrowserLaunchConfig {
10
- prepare: (userDataDir: string, devtoolsPort: number) => Promise<{
11
- args: string[];
12
- startingUrl?: string;
13
- cleanup?: () => Promise<void>;
14
- }>;
15
- }
16
-
17
-
18
-
19
-
20
- export async function launchBrowserBase(
21
- opts: BrowserStartOptions,
22
- config: BrowserLaunchConfig
23
- ): Promise<BrowserResult> {
24
- const { userDataDir } = makeUniqueBrowserConfig();
25
- // Ensure userDataDir exists
26
- fs.mkdirSync(userDataDir, { recursive: true });
27
-
28
- let hookResult: Awaited<ReturnType<BrowserLaunchConfig['prepare']>> | undefined;
29
- try {
30
- const devtoolsPort = await portfinder.getPortPromise({ port: 41000, stopPort: 49999 });
31
-
32
- hookResult = await config.prepare(userDataDir, devtoolsPort);
33
-
34
- const args = [
35
- `--user-data-dir=${userDataDir}`,
36
- `--remote-debugging-port=${devtoolsPort}`,
37
- `--remote-debugging-address=0.0.0.0`,
38
- ...hookResult.args
39
- ];
40
-
41
- // Handle headless option if not already handled by provider
42
- if (opts.headless !== false && !args.some(a => a.startsWith("--headless"))) {
43
- args.push("--headless");
44
- }
45
-
46
- const brw = await cl.launch({
47
- userDataDir,
48
- port: devtoolsPort,
49
- chromePath: opts.chromePath,
50
- chromeFlags: args,
51
- startingUrl: hookResult.startingUrl || "about:blank"
52
- });
53
- const wsUrl = await getBrowserWebSocketUrl(brw.port)
54
-
55
- return {
56
- userDataDir,
57
- port: brw.port,
58
- browser: brw,
59
- wsUrl,
60
- close: async () => {
61
- await tryCatch(async () => await brw.kill());
62
- if (hookResult?.cleanup) {
63
- await tryCatch(hookResult.cleanup);
64
- }
65
- await tryLoop(async () => fs.rmSync(userDataDir, { recursive: true, force: true }));
66
- },
67
- async mainPage() {
68
- const browser = await chromium.connectOverCDP(wsUrl)
69
- const ctx = browser.contexts()?.[0] ?? await browser.newContext()
70
- const page = ctx?.pages()?.[0] ?? await ctx.newPage()
71
- return page;
72
- }
73
- };
74
- } catch (e) {
75
- // cleanup immediately if launch fails
76
- await tryLoop(async () => fs.rmSync(userDataDir, { recursive: true, force: true }));
77
- if (hookResult?.cleanup) await tryCatch(hookResult.cleanup);
78
- throw e;
79
- }
80
- }
@@ -1,40 +0,0 @@
1
- import type { BrowserStartOptions, BrowserResult } from "../types";
2
- import * as cl from "chrome-launcher";
3
- import { getBrowserWebSocketUrl } from "../core/launcher";
4
- import { chromium } from "patchright-core";
5
-
6
- export async function startLocalBrowser(opts: BrowserStartOptions): Promise<BrowserResult> {
7
- const { chromePath, headless = false, userDataDir } = opts;
8
-
9
- const chromeFlags = [
10
- "--disable-blink-features=AutomationControlled",
11
- "--no-sandbox",
12
- "--disable-setuid-sandbox",
13
- ];
14
-
15
- if (headless) {
16
- chromeFlags.push("--headless");
17
- }
18
-
19
- const browser = await cl.launch({
20
- chromePath,
21
- chromeFlags,
22
- userDataDir,
23
- });
24
-
25
- const wsUrl = await getBrowserWebSocketUrl(browser.port);
26
-
27
- return {
28
- userDataDir: userDataDir || "",
29
- port: browser.port,
30
- browser: browser,
31
- wsUrl,
32
- close: async () => await browser.kill(),
33
- async mainPage() {
34
- const brw = await chromium.connectOverCDP(wsUrl)
35
- const ctx = brw.contexts()?.[0] ?? await brw.newContext()
36
- const page = ctx?.pages()?.[0] ?? await ctx.newPage()
37
- return page;
38
- }
39
- };
40
- }
@@ -1,102 +0,0 @@
1
- import { faker } from "@faker-js/faker";
2
- import type { BrowserResult, BrowserStartOptions } from "../types";
3
- import { getIpInfo, startProxyServer, type ProxyServerResult } from "@tocha688/utils";
4
- import { launchBrowserBase } from "./base";
5
- import fs from "node:fs";
6
- import path from "node:path";
7
-
8
- export async function OKBrowserStartMain(opts: BrowserStartOptions): Promise<BrowserResult> {
9
- return launchBrowserBase(opts, {
10
- prepare: async (userDataDir, devtoolsPort) => {
11
- let proxy: ProxyServerResult | undefined;
12
- if (opts.proxy) {
13
- proxy = await startProxyServer(opts.proxy);
14
- console.log(`Started proxy server on port ${proxy.port}`);
15
- }
16
- let ipinfo: any = proxy?.ipinfo;
17
- if (ipinfo) {
18
- //获取本地IP
19
- ipinfo = await getIpInfo(ipinfo.proxy);
20
- }
21
-
22
-
23
- const fingerprintPath = path.join(userDataDir, "fingerprint.config");
24
- let fingerprint: string;
25
-
26
- if (fs.existsSync(fingerprintPath)) {
27
- fingerprint = fs.readFileSync(fingerprintPath, "utf-8");
28
- } else {
29
- fingerprint = faker.number.int({ min: 10000000, max: 99999999 }).toString();
30
- fs.writeFileSync(fingerprintPath, fingerprint);
31
- }
32
-
33
- const args = [
34
- "--allow-pre-commit-input",
35
- "--disable-background-networking",
36
- "--disable-background-timer-throttling",
37
- "--disable-backgrounding-occluded-windows",
38
- "--disable-breakpad",
39
- "--disable-client-side-phishing-detection",
40
- "--disable-component-extensions-with-background-pages",
41
- "--disable-crash-reporter",
42
- "--disable-default-apps",
43
- "--disable-dev-shm-usage",
44
- "--disable-hang-monitor",
45
- "--disable-infobars",
46
- "--disable-ipc-flooding-protection",
47
- "--disable-popup-blocking",
48
- "--disable-prompt-on-repost",
49
- "--disable-renderer-backgrounding",
50
- "--disable-search-engine-choice-screen",
51
- "--disable-sync",
52
- "--export-tagged-pdf",
53
- "--force-color-profile=srgb",
54
- "--generate-pdf-document-outline",
55
- "--metrics-recording-only",
56
- "--no-first-run",
57
- "--password-store=basic",
58
- "--use-mock-keychain",
59
- "--disable-features=Translate,AcceptCHFrame,MediaRouter,OptimizationHints,ProcessPerSiteUpToMainFrameThreshold,IsolateSandboxedIframes",
60
- "--enable-features=PdfOopif",
61
- // "--user-data-dir=" + userDataDir, // Handled by base
62
- // "about:blank",
63
- // "http://127.0.0.1:4252/index.html?id=1977283458602381314",
64
- // "--fingerprints=37553310",
65
- "--fingerprints=" + fingerprint,
66
- "--window-size=1280,720",
67
- "--window-position=0,0",
68
- "--no-sandbox",
69
- // "--disable-blink-features=AutomationControlled",
70
- "--ignore-certificate-errors",
71
- "--notice-number=1",
72
- // "--notice-number=4",
73
- // "--load-extension=",
74
- // "--remote-debugging-port=" + devtoolsPort, // Handled by base
75
- // "--remote-debugging-address=0.0.0.0", // Handled by base
76
- // "--enable-password-manager",
77
- "--ignores=tls",
78
- "--enable-logging",
79
- // "--proxy-server=http://127.0.0.1:" + proxy.port,
80
- "--timezone=" + (ipinfo?.timezone ?? "America/Los_Angeles"),
81
- "--lang=en-US",
82
- // "--headless", // Handled by base
83
- ];
84
-
85
- if (proxy && proxy.port) {
86
- args.push(`--proxy-server=http://127.0.0.1:${proxy.port}`);
87
- }
88
-
89
- return {
90
- args,
91
- startingUrl: "https://ipapi.co/json/",
92
- cleanup: async () => {
93
- if (proxy) await proxy.server.close(true);
94
- }
95
- };
96
- }
97
- });
98
- }
99
-
100
- export async function OKBrowserCreate(opts: BrowserStartOptions) {
101
- return OKBrowserStartMain(opts);
102
- }
@@ -1,24 +0,0 @@
1
- import type { ProxyFormatInfo } from "@tocha688/utils/ip";
2
- import * as cl from "chrome-launcher"
3
- import type { Page } from "patchright-core";
4
- import * as ProxyChain from "proxy-chain";
5
-
6
- // 使用方式
7
- export type BrowserStartOptions = {
8
- proxy?: string,
9
- headless?: boolean,
10
- chromePath: string,
11
- userDataDir?: string;
12
- }
13
- export type BrowserResult = {
14
- userDataDir: string,
15
- port: number,
16
- browser: cl.LaunchedChrome,
17
- close: Function,
18
- wsUrl: string,
19
- mainPage:()=>Promise<Page>
20
- }
21
-
22
- export type StartBrowserFn = (opts: BrowserStartOptions) => Promise<BrowserResult>;
23
-
24
- export type ProxyServerResult = { port: number, server: ProxyChain.Server, ipinfo: any }
package/tsconfig.json DELETED
@@ -1,29 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- // Environment setup & latest features
4
- "lib": ["ESNext"],
5
- "target": "ESNext",
6
- "module": "Preserve",
7
- "moduleDetection": "force",
8
- "jsx": "react-jsx",
9
- "allowJs": true,
10
-
11
- // Bundler mode
12
- "moduleResolution": "bundler",
13
- "allowImportingTsExtensions": true,
14
- "verbatimModuleSyntax": true,
15
- "noEmit": true,
16
-
17
- // Best practices
18
- "strict": true,
19
- "skipLibCheck": true,
20
- "noFallthroughCasesInSwitch": true,
21
- "noUncheckedIndexedAccess": true,
22
- "noImplicitOverride": true,
23
-
24
- // Some stricter flags (disabled by default)
25
- "noUnusedLocals": false,
26
- "noUnusedParameters": false,
27
- "noPropertyAccessFromIndexSignature": false
28
- }
29
- }
package/tsup.config.ts DELETED
@@ -1,14 +0,0 @@
1
- import { defineConfig } from 'tsup';
2
-
3
- export default defineConfig({
4
- entry: ['src/index.ts'],
5
- format: ['cjs', 'esm'],
6
- clean: true,
7
- minify: true,
8
- shims: true,
9
- dts: true,
10
- splitting: false,
11
- sourcemap: false,
12
- platform: 'node',
13
- target: 'esnext',
14
- });