UNPKG

brave-real-playwright-core

Version:

Brave-optimized Playwright Core (v1.55.0) with comprehensive stealth patches and error stack sanitization

447 lines (446 loc) 16 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var bidiBrowser_exports = {}; __export(bidiBrowser_exports, { BidiBrowser: () => BidiBrowser, BidiBrowserContext: () => BidiBrowserContext, Network: () => Network }); module.exports = __toCommonJS(bidiBrowser_exports); var import_eventsHelper = require("../utils/eventsHelper"); var import_browser = require("../browser"); var import_browserContext = require("../browserContext"); var network = __toESM(require("../network")); var import_bidiConnection = require("./bidiConnection"); var import_bidiNetworkManager = require("./bidiNetworkManager"); var import_bidiPage = require("./bidiPage"); var import_page = require("../page"); var bidi = __toESM(require("./third_party/bidiProtocol")); class BidiBrowser extends import_browser.Browser { constructor(parent, transport, options) { super(parent, options); this._contexts = /* @__PURE__ */ new Map(); this._bidiPages = /* @__PURE__ */ new Map(); this._connection = new import_bidiConnection.BidiConnection(transport, this._onDisconnect.bind(this), options.protocolLogger, options.browserLogsCollector); this._browserSession = this._connection.browserSession; this._eventListeners = [ import_eventsHelper.eventsHelper.addEventListener(this._browserSession, "browsingContext.contextCreated", this._onBrowsingContextCreated.bind(this)), import_eventsHelper.eventsHelper.addEventListener(this._browserSession, "script.realmDestroyed", this._onScriptRealmDestroyed.bind(this)) ]; } static async connect(parent, transport, options) { const browser = new BidiBrowser(parent, transport, options); if (options.__testHookOnConnectToBrowser) await options.__testHookOnConnectToBrowser(); browser._bidiSessionInfo = await browser._browserSession.send("session.new", { capabilities: { alwaysMatch: { acceptInsecureCerts: options.persistent?.internalIgnoreHTTPSErrors || options.persistent?.ignoreHTTPSErrors, proxy: getProxyConfiguration(options.originalLaunchOptions.proxyOverride ?? options.proxy), unhandledPromptBehavior: { default: bidi.Session.UserPromptHandlerType.Ignore }, webSocketUrl: true } } }); await browser._browserSession.send("session.subscribe", { events: [ "browsingContext", "network", "log", "script" ] }); if (options.persistent) { const context = new BidiBrowserContext(browser, void 0, options.persistent); browser._defaultContext = context; await context._initialize(); const page = await browser._defaultContext.doCreateNewPage(); await page.waitForInitializedOrError(); } return browser; } _onDisconnect() { this._didClose(); } async doCreateNewContext(options) { const proxy = options.proxyOverride || options.proxy; const { userContext } = await this._browserSession.send("browser.createUserContext", { acceptInsecureCerts: options.internalIgnoreHTTPSErrors || options.ignoreHTTPSErrors, proxy: getProxyConfiguration(proxy) }); const context = new BidiBrowserContext(this, userContext, options); await context._initialize(); this._contexts.set(userContext, context); return context; } contexts() { return Array.from(this._contexts.values()); } version() { return this._bidiSessionInfo.capabilities.browserVersion; } userAgent() { return this._bidiSessionInfo.capabilities.userAgent; } isConnected() { return !this._connection.isClosed(); } _onBrowsingContextCreated(event) { if (event.parent) { const parentFrameId = event.parent; for (const page2 of this._bidiPages.values()) { const parentFrame = page2._page.frameManager.frame(parentFrameId); if (!parentFrame) continue; page2._session.addFrameBrowsingContext(event.context); page2._page.frameManager.frameAttached(event.context, parentFrameId); const frame = page2._page.frameManager.frame(event.context); if (frame) frame._url = event.url; return; } return; } let context = this._contexts.get(event.userContext); if (!context) context = this._defaultContext; if (!context) return; const session = this._connection.createMainFrameBrowsingContextSession(event.context); const opener = event.originalOpener && this._bidiPages.get(event.originalOpener); const page = new import_bidiPage.BidiPage(context, session, opener || null); page._page.mainFrame()._url = event.url; this._bidiPages.set(event.context, page); } _onBrowsingContextDestroyed(event) { if (event.parent) { this._browserSession.removeFrameBrowsingContext(event.context); const parentFrameId = event.parent; for (const page of this._bidiPages.values()) { const parentFrame = page._page.frameManager.frame(parentFrameId); if (!parentFrame) continue; page._page.frameManager.frameDetached(event.context); return; } return; } const bidiPage = this._bidiPages.get(event.context); if (!bidiPage) return; bidiPage.didClose(); this._bidiPages.delete(event.context); } _onScriptRealmDestroyed(event) { for (const page of this._bidiPages.values()) { if (page._onRealmDestroyed(event)) return; } } } class BidiBrowserContext extends import_browserContext.BrowserContext { constructor(browser, browserContextId, options) { super(browser, options, browserContextId); this._originToPermissions = /* @__PURE__ */ new Map(); this._initScriptIds = /* @__PURE__ */ new Map(); this._authenticateProxyViaHeader(); } _bidiPages() { return [...this._browser._bidiPages.values()].filter((bidiPage) => bidiPage._browserContext === this); } async _initialize() { const promises = [ super._initialize() ]; promises.push(this.doUpdateDefaultViewport()); if (this._options.geolocation) promises.push(this.setGeolocation(this._options.geolocation)); if (this._options.locale) { promises.push(this._browser._browserSession.send("emulation.setLocaleOverride", { locale: this._options.locale, userContexts: [this._userContextId()] })); } await Promise.all(promises); } possiblyUninitializedPages() { return this._bidiPages().map((bidiPage) => bidiPage._page); } async doCreateNewPage() { const { context } = await this._browser._browserSession.send("browsingContext.create", { type: bidi.BrowsingContext.CreateType.Window, userContext: this._browserContextId }); return this._browser._bidiPages.get(context)._page; } async doGetCookies(urls) { const { cookies } = await this._browser._browserSession.send( "storage.getCookies", { partition: { type: "storageKey", userContext: this._browserContextId } } ); return network.filterCookies(cookies.map((c) => { const copy = { name: c.name, value: (0, import_bidiNetworkManager.bidiBytesValueToString)(c.value), domain: c.domain, path: c.path, httpOnly: c.httpOnly, secure: c.secure, expires: c.expiry ?? -1, sameSite: c.sameSite ? fromBidiSameSite(c.sameSite) : "None" }; return copy; }), urls); } async addCookies(cookies) { cookies = network.rewriteCookies(cookies); const promises = cookies.map((c) => { const cookie = { name: c.name, value: { type: "string", value: c.value }, domain: c.domain, path: c.path, httpOnly: c.httpOnly, secure: c.secure, sameSite: c.sameSite && toBidiSameSite(c.sameSite), expiry: c.expires === -1 || c.expires === void 0 ? void 0 : Math.round(c.expires) }; return this._browser._browserSession.send( "storage.setCookie", { cookie, partition: { type: "storageKey", userContext: this._browserContextId } } ); }); await Promise.all(promises); } async doClearCookies() { await this._browser._browserSession.send( "storage.deleteCookies", { partition: { type: "storageKey", userContext: this._browserContextId } } ); } async doGrantPermissions(origin, permissions) { const currentPermissions = this._originToPermissions.get(origin) || []; const toGrant = permissions.filter((permission) => !currentPermissions.includes(permission)); this._originToPermissions.set(origin, [...currentPermissions, ...toGrant]); await Promise.all(toGrant.map((permission) => this._setPermission(origin, permission, bidi.Permissions.PermissionState.Granted))); } async doClearPermissions() { const currentPermissions = [...this._originToPermissions.entries()]; this._originToPermissions = /* @__PURE__ */ new Map(); await Promise.all(currentPermissions.map(([origin, permissions]) => permissions.map( (p) => this._setPermission(origin, p, bidi.Permissions.PermissionState.Prompt) ))); } async _setPermission(origin, permission, state) { await this._browser._browserSession.send("permissions.setPermission", { descriptor: { name: permission }, state, origin, userContext: this._userContextId() }); } async setGeolocation(geolocation) { (0, import_browserContext.verifyGeolocation)(geolocation); this._options.geolocation = geolocation; await this._browser._browserSession.send("emulation.setGeolocationOverride", { coordinates: geolocation ? { latitude: geolocation.latitude, longitude: geolocation.longitude, accuracy: geolocation.accuracy } : null, userContexts: [this._userContextId()] }); } async doUpdateExtraHTTPHeaders() { } async setUserAgent(userAgent) { } async doUpdateOffline() { } async doSetHTTPCredentials(httpCredentials) { this._options.httpCredentials = httpCredentials; for (const page of this.pages()) await page.delegate.updateHttpCredentials(); } async doAddInitScript(initScript) { const { script } = await this._browser._browserSession.send("script.addPreloadScript", { // TODO: remove function call from the source. functionDeclaration: `() => { return ${initScript.source} }`, userContexts: [this._userContextId()] }); this._initScriptIds.set(initScript, script); } async doRemoveInitScripts(initScripts) { const ids = []; for (const script of initScripts) { const id = this._initScriptIds.get(script); if (id) ids.push(id); this._initScriptIds.delete(script); } await Promise.all(ids.map((script) => this._browser._browserSession.send("script.removePreloadScript", { script }))); } async doUpdateRequestInterception() { } async doUpdateDefaultViewport() { if (!this._options.viewport) return; await this._browser._browserSession.send("browsingContext.setViewport", { viewport: { width: this._options.viewport.width, height: this._options.viewport.height }, devicePixelRatio: this._options.deviceScaleFactor || 1, userContexts: [this._userContextId()] }); } async doUpdateDefaultEmulatedMedia() { } async doExposePlaywrightBinding() { const args = [{ type: "channel", value: { channel: import_bidiPage.kPlaywrightBindingChannel, ownership: bidi.Script.ResultOwnership.Root } }]; const functionDeclaration = `function addMainBinding(callback) { globalThis['${import_page.PageBinding.kBindingName}'] = callback; }`; const promises = []; promises.push(this._browser._browserSession.send("script.addPreloadScript", { functionDeclaration, arguments: args, userContexts: [this._userContextId()] })); promises.push(...this._bidiPages().map((page) => { const realms = [...page._realmToContext].filter(([realm, context]) => context.world === "main").map(([realm, context]) => realm); return Promise.all(realms.map((realm) => { return page._session.send("script.callFunction", { functionDeclaration, arguments: args, target: { realm }, awaitPromise: false, userActivation: false }); })); })); await Promise.all(promises); } onClosePersistent() { } async clearCache() { } async doClose(reason) { if (!this._browserContextId) { await this._browser.close({ reason }); return; } await this._browser._browserSession.send("browser.removeUserContext", { userContext: this._browserContextId }); this._browser._contexts.delete(this._browserContextId); } async cancelDownload(uuid) { } _userContextId() { if (this._browserContextId) return this._browserContextId; return "default"; } } function fromBidiSameSite(sameSite) { switch (sameSite) { case "strict": return "Strict"; case "lax": return "Lax"; case "none": return "None"; } return "None"; } function toBidiSameSite(sameSite) { switch (sameSite) { case "Strict": return bidi.Network.SameSite.Strict; case "Lax": return bidi.Network.SameSite.Lax; case "None": return bidi.Network.SameSite.None; } return bidi.Network.SameSite.None; } function getProxyConfiguration(proxySettings) { if (!proxySettings) return void 0; const proxy = { proxyType: "manual" }; const url = new URL(proxySettings.server); switch (url.protocol) { case "http:": proxy.httpProxy = url.host; break; case "https:": proxy.sslProxy = url.host; break; case "socks4:": proxy.socksProxy = url.host; proxy.socksVersion = 4; break; case "socks5:": proxy.socksProxy = url.host; proxy.socksVersion = 5; break; default: throw new Error("Invalid proxy server protocol: " + proxySettings.server); } const bypass = proxySettings.bypass ?? process.env.PLAYWRIGHT_PROXY_BYPASS_FOR_TESTING; if (bypass) proxy.noProxy = bypass.split(","); return proxy; } var Network; ((Network2) => { let SameSite; ((SameSite2) => { SameSite2["Strict"] = "strict"; SameSite2["Lax"] = "lax"; SameSite2["None"] = "none"; })(SameSite = Network2.SameSite || (Network2.SameSite = {})); })(Network || (Network = {})); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { BidiBrowser, BidiBrowserContext, Network });