mirror of
https://github.com/FlareSolverr/FlareSolverr.git
synced 2025-06-08 12:35:30 +00:00
188 lines
5.2 KiB
TypeScript
188 lines
5.2 KiB
TypeScript
import {v1 as UUIDv1} from 'uuid'
|
|
import * as path from 'path'
|
|
import {Browser} from 'puppeteer'
|
|
import {Protocol} from "devtools-protocol";
|
|
|
|
import log from './log'
|
|
import {Proxy} from "../controllers/v1";
|
|
|
|
const os = require('os');
|
|
const fs = require('fs');
|
|
const puppeteer = require('puppeteer');
|
|
|
|
export interface SessionsCacheItem {
|
|
sessionId: string
|
|
browser: Browser
|
|
}
|
|
|
|
interface SessionsCache {
|
|
[key: string]: SessionsCacheItem
|
|
}
|
|
|
|
export interface SessionCreateOptions {
|
|
oneTimeSession: boolean
|
|
cookies?: Protocol.Network.CookieParam[],
|
|
maxTimeout?: number
|
|
proxy?: Proxy
|
|
}
|
|
|
|
const sessionCache: SessionsCache = {}
|
|
let webBrowserUserAgent: string;
|
|
|
|
function buildExtraPrefsFirefox(proxy: Proxy): object {
|
|
// Default configurations are defined here
|
|
// https://github.com/puppeteer/puppeteer/blob/v3.3.0/src/Launcher.ts#L481
|
|
const extraPrefsFirefox = {
|
|
// Disable newtabpage
|
|
"browser.newtabpage.enabled": false,
|
|
"browser.startup.homepage": "about:blank",
|
|
|
|
// Do not warn when closing all open tabs
|
|
"browser.tabs.warnOnClose": false,
|
|
|
|
// Disable telemetry
|
|
"toolkit.telemetry.reportingpolicy.firstRun": false,
|
|
|
|
// Disable first-run welcome page
|
|
"startup.homepage_welcome_url": "about:blank",
|
|
"startup.homepage_welcome_url.additional": "",
|
|
|
|
// Detected !
|
|
// // Disable images to speed up load
|
|
// "permissions.default.image": 2,
|
|
|
|
// Limit content processes to 1
|
|
"dom.ipc.processCount": 1
|
|
}
|
|
|
|
// proxy.url format => http://<host>:<port>
|
|
if (proxy && proxy.url) {
|
|
const [host, portStr] = proxy.url.replace(/.+:\/\//g, '').split(':');
|
|
const port = parseInt(portStr);
|
|
|
|
const proxyPrefs = {
|
|
"network.proxy.type": 1,
|
|
"network.proxy.share_proxy_settings": true
|
|
}
|
|
if (proxy.url.indexOf("socks") != -1) {
|
|
// SOCKSv4 & SOCKSv5
|
|
Object.assign(proxyPrefs, {
|
|
"network.proxy.socks": host,
|
|
"network.proxy.socks_port": port,
|
|
"network.proxy.socks_remote_dns": true
|
|
});
|
|
if (proxy.url.indexOf("socks4") != -1) {
|
|
Object.assign(proxyPrefs, {
|
|
"network.proxy.socks_version": 4
|
|
});
|
|
} else {
|
|
Object.assign(proxyPrefs, {
|
|
"network.proxy.socks_version": 5
|
|
});
|
|
}
|
|
} else {
|
|
// HTTP
|
|
Object.assign(proxyPrefs, {
|
|
"network.proxy.ftp": host,
|
|
"network.proxy.ftp_port": port,
|
|
"network.proxy.http": host,
|
|
"network.proxy.http_port": port,
|
|
"network.proxy.ssl": host,
|
|
"network.proxy.ssl_port": port
|
|
});
|
|
}
|
|
|
|
// merge objects
|
|
Object.assign(extraPrefsFirefox, proxyPrefs);
|
|
}
|
|
|
|
return extraPrefsFirefox;
|
|
}
|
|
|
|
export function getUserAgent() {
|
|
return webBrowserUserAgent
|
|
}
|
|
|
|
export async function testWebBrowserInstallation(): Promise<void> {
|
|
log.info("Testing web browser installation...")
|
|
|
|
// check user home dir. this dir will be used by Firefox
|
|
const homeDir = os.homedir();
|
|
fs.accessSync(homeDir, fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK | fs.constants.X_OK);
|
|
log.debug("FlareSolverr user home directory is OK: " + homeDir)
|
|
|
|
// test web browser
|
|
const testUrl = process.env.TEST_URL || "https://www.google.com";
|
|
log.debug("Test URL: " + testUrl)
|
|
const session = await create(null, {
|
|
oneTimeSession: true
|
|
})
|
|
const page = await session.browser.newPage()
|
|
await page.goto(testUrl)
|
|
webBrowserUserAgent = await page.evaluate(() => navigator.userAgent)
|
|
|
|
// replace Linux ARM user-agent because it's detected
|
|
if (["arm", "aarch64"].some(arch => webBrowserUserAgent.toLocaleLowerCase().includes('linux ' + arch))) {
|
|
webBrowserUserAgent = webBrowserUserAgent.replace(/linux \w+;/i, 'Linux x86_64;')
|
|
}
|
|
|
|
log.info("FlareSolverr User-Agent: " + webBrowserUserAgent)
|
|
await page.close()
|
|
await destroy(session.sessionId)
|
|
|
|
log.info("Test successful")
|
|
}
|
|
|
|
export async function create(session: string, options: SessionCreateOptions): Promise<SessionsCacheItem> {
|
|
const sessionId = session || UUIDv1()
|
|
|
|
// NOTE: cookies can't be set in the session, you need to open the page first
|
|
|
|
const puppeteerOptions: any = {
|
|
product: 'firefox',
|
|
headless: process.env.HEADLESS !== 'false',
|
|
timeout: process.env.BROWSER_TIMEOUT || 30000
|
|
}
|
|
|
|
puppeteerOptions.extraPrefsFirefox = buildExtraPrefsFirefox(options.proxy)
|
|
|
|
// if we are running inside executable binary, change browser path
|
|
if (typeof (process as any).pkg !== 'undefined') {
|
|
const exe = process.platform === "win32" ? 'firefox.exe' : 'firefox';
|
|
puppeteerOptions.executablePath = path.join(path.dirname(process.execPath), 'firefox', exe)
|
|
}
|
|
|
|
log.debug('Launching web browser...')
|
|
let browser: Browser = await puppeteer.launch(puppeteerOptions)
|
|
if (!browser) {
|
|
throw Error(`Failed to launch web browser.`)
|
|
}
|
|
|
|
sessionCache[sessionId] = {
|
|
sessionId: sessionId,
|
|
browser: browser
|
|
}
|
|
|
|
return sessionCache[sessionId]
|
|
}
|
|
|
|
export function list(): string[] {
|
|
return Object.keys(sessionCache)
|
|
}
|
|
|
|
export async function destroy(id: string): Promise<boolean>{
|
|
if (id && sessionCache.hasOwnProperty(id)) {
|
|
const { browser } = sessionCache[id]
|
|
if (browser) {
|
|
await browser.close()
|
|
delete sessionCache[id]
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
export function get(id: string): SessionsCacheItem {
|
|
return sessionCache[id]
|
|
}
|