UNPKG

fakebrowser

Version:

🤖 Fake fingerprints to bypass anti-bot systems. Simulate mouse and keyboard operations to make behavior like a real person.

220 lines • 19.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BrowserLauncher = void 0; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const URLToolkit = __importStar(require("url-toolkit")); const http = __importStar(require("http")); const url = __importStar(require("url")); const axios_1 = __importDefault(require("axios")); const https_1 = require("https"); const assert_1 = require("assert"); const Driver_js_1 = __importDefault(require("./Driver.js")); const DeviceDescriptor_js_1 = __importDefault(require("./DeviceDescriptor.js")); const PptrPatcher_1 = require("./PptrPatcher"); const FakeBrowser_1 = require("./FakeBrowser"); const kFakeDDFileName = '__fakebrowser_fakeDD.json'; const kInternalHttpServerHeartbeatMagic = '__fakebrowser__&88ff22--'; class BrowserLauncher { static checkLaunchOptionsLegal(options) { if (!options || !options.args || !options.args.length) { return; } // These args are set by FakeBrowser and cannot be set externally: const externalCannotSetArgs = [ '--user-data-dir', '--lang', '--window-position', '--window-size', ]; if (options.args.filter(e => externalCannotSetArgs.includes(e.toLocaleLowerCase().split('=')[0])).length > 0) { throw new TypeError(`${externalCannotSetArgs} cannot be set in options.args`); } } static prepareFakeDeviceDesc(params) { // Go to the userDataDir specified by the user and read the __fakebrowser_fakeDD.json file // or create it if it does not exist. const userDataDir = params.userDataDir; (0, assert_1.strict)(userDataDir); if (!fs.existsSync(userDataDir)) { // may throw fs.mkdirSync(userDataDir, { recursive: true }); } // Read from existing files, or generate if not available. const fakeDDPathName = path.resolve(userDataDir, `./${kFakeDDFileName}`); let tempFakeDD = null; try { tempFakeDD = (fs.existsSync(fakeDDPathName) ? fs.readJsonSync(fakeDDPathName) : params.deviceDesc); DeviceDescriptor_js_1.default.checkLegal(tempFakeDD); } catch (ex) { console.warn('FakeDD illegal'); // It is possible that some fields are missing due to the deviceDesc update and need to recreate fakeDD const orgTempFakeDD = tempFakeDD; tempFakeDD = params.deviceDesc; if (orgTempFakeDD) { tempFakeDD.fontSalt = orgTempFakeDD.fontSalt; tempFakeDD.canvasSalt = orgTempFakeDD.canvasSalt; } } const { fakeDeviceDesc, needsUpdate, } = DeviceDescriptor_js_1.default.buildFakeDeviceDescriptor(tempFakeDD); if (needsUpdate) { fs.writeJsonSync(fakeDDPathName, fakeDeviceDesc, { spaces: 2 }); } params.fakeDeviceDesc = fakeDeviceDesc; } static async connect(params) { await this.bootInternalHTTPServer(); this.prepareFakeDeviceDesc(params); (0, assert_1.strict)(params.fakeDeviceDesc); const uuid = DeviceDescriptor_js_1.default.deviceUUID(params.fakeDeviceDesc); const { vanillaBrowser, pptrExtra, } = await Driver_js_1.default.connect(uuid, params); const launchTime = new Date().getTime(); const fb = new FakeBrowser_1.FakeBrowser(params, vanillaBrowser, pptrExtra, launchTime, uuid); // pages 0 cannot be hook, lets drop it await fb._patchPages0Bug(); return fb; } static async launch(params) { this.bootBrowserSurvivalChecker(); await this.bootInternalHTTPServer(); // deviceDesc, userDataDir cannot be empty this.checkLaunchOptionsLegal(params.launchOptions); this.prepareFakeDeviceDesc(params); (0, assert_1.strict)(params.fakeDeviceDesc); const uuid = DeviceDescriptor_js_1.default.deviceUUID(params.fakeDeviceDesc); const { vanillaBrowser, pptrExtra, } = await Driver_js_1.default.launch(uuid, FakeBrowser_1.FakeBrowser.globalConfig.defaultLaunchArgs, params); const launchTime = new Date().getTime(); const fb = new FakeBrowser_1.FakeBrowser(params, vanillaBrowser, pptrExtra, launchTime, uuid); // pages 0 cannot be hook, lets drop it await fb._patchPages0Bug(); // Manage surviving browsers and kill them if they time out this._fakeBrowserInstances.push(fb); return fb; } static async bootInternalHTTPServer() { if (!this._httpServer) { this._httpServer = http.createServer(); this._httpServer.on('request', async (req, res) => { (0, assert_1.strict)(req.url); const { query, pathname } = url.parse(req.url, true); if (pathname === '/hb') { res.write(kInternalHttpServerHeartbeatMagic); res.end(); } if (pathname === '/patchWorker') { const relUrl = query['relUrl']; const workerUrl = query['workerUrl']; const uuid = query['uuid']; const fullUrl = URLToolkit.buildAbsoluteURL(relUrl, workerUrl); console.log('request worker content from: ', fullUrl); // Object.fromEntries ES2019 const reqHeaders = Object.fromEntries(Object.entries(req.headers).map(e => ([e[0], e[1][0]]))); delete reqHeaders['host']; // TODO: get through proxy const jsResp = await axios_1.default.get(fullUrl, { headers: reqHeaders, httpsAgent: new https_1.Agent({ rejectUnauthorized: false, }), }); let jsContent = jsResp.data; const browser = BrowserLauncher.getBrowserWithUUID(uuid); if (browser) { jsContent = await PptrPatcher_1.PptrPatcher.patchWorkerJsContent(browser, jsContent); } const respHeaders = jsResp.headers; delete respHeaders['content-length']; res.writeHead(jsResp.status, jsResp.statusText, respHeaders); res.write(jsContent); res.end(); } }); // If the port listens to errors, determine if the heartbeat interface is successful try { this._httpServer.listen(FakeBrowser_1.FakeBrowser.globalConfig.internalHttpServerPort); } catch (ex) { const hbUrl = `http://127.0.0.1:${FakeBrowser_1.FakeBrowser.globalConfig.internalHttpServerPort}/hb`; try { const hbData = (await axios_1.default.get(hbUrl)).data; if (hbData === kInternalHttpServerHeartbeatMagic) { try { this._httpServer.close(); } finally { this._httpServer = null; } return; } } catch (ignore) { } throw ex; } } } static bootBrowserSurvivalChecker() { if (!this._checkerIntervalId) { this._checkerIntervalId = setInterval(async () => { const killThese = this._fakeBrowserInstances.filter(e => (e.launchParams.maxSurvivalTime > 0) && (new Date().getTime() > e.bindingTime + e.launchParams.maxSurvivalTime)); const p = []; for (const fb of killThese) { p.push(fb.shutdown()); } await Promise.all(p); }, 5 * 1000); } } static getBrowserWithUUID(uuid) { return this._fakeBrowserInstances.find(e => e.uuid === uuid); } static async _forceShutdown(fb) { await Driver_js_1.default.shutdown(fb.vanillaBrowser); const browserIndex = this._fakeBrowserInstances.indexOf(fb); (0, assert_1.strict)(browserIndex >= 0); this._fakeBrowserInstances.splice(browserIndex, 1); // If all browsers have exited, close internal http service if (this._fakeBrowserInstances.length === 0) { // console.log('close appserver') if (this._httpServer) { try { this._httpServer.close(); } finally { this._httpServer = null; } } } } } exports.BrowserLauncher = BrowserLauncher; BrowserLauncher._fakeBrowserInstances = []; BrowserLauncher._checkerIntervalId = null; BrowserLauncher._httpServer = null; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQnJvd3NlckxhdW5jaGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvcmUvQnJvd3NlckxhdW5jaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSw2Q0FBOEI7QUFDOUIsMkNBQTRCO0FBQzVCLHdEQUF5QztBQUN6QywyQ0FBNEI7QUFFNUIseUNBQTBCO0FBRTFCLGtEQUF5QjtBQUN6QixpQ0FBMkI7QUFDM0IsbUNBQXVDO0FBRXZDLDREQUErRztBQUMvRyxnRkFBa0Y7QUFDbEYsK0NBQXlDO0FBQ3pDLCtDQUF5QztBQUV6QyxNQUFNLGVBQWUsR0FBRywyQkFBMkIsQ0FBQTtBQUNuRCxNQUFNLGlDQUFpQyxHQUFHLDBCQUEwQixDQUFBO0FBRXBFLE1BQWEsZUFBZTtJQU1oQixNQUFNLENBQUMsdUJBQXVCLENBQUMsT0FBOEI7UUFDakUsSUFBSSxDQUFDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNuRCxPQUFNO1NBQ1Q7UUFFRCxrRUFBa0U7UUFDbEUsTUFBTSxxQkFBcUIsR0FBRztZQUMxQixpQkFBaUI7WUFDakIsUUFBUTtZQUNSLG1CQUFtQjtZQUNuQixlQUFlO1NBQ2xCLENBQUE7UUFFRCxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUNuQixDQUFDLENBQUMsRUFBRSxDQUFDLHFCQUFxQixDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FDM0UsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQ1YsTUFBTSxJQUFJLFNBQVMsQ0FBQyxHQUFHLHFCQUFxQixnQ0FBZ0MsQ0FBQyxDQUFBO1NBQ2hGO0lBQ0wsQ0FBQztJQUVPLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxN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