UNPKG

rebrowser-playwright-core

Version:

A drop-in replacement for playwright-core patched with rebrowser-patches. It allows to pass modern automation detection tests.

311 lines (309 loc) 11.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Network = exports.BidiBrowserContext = exports.BidiBrowser = void 0; var _eventsHelper = require("../../utils/eventsHelper"); var _browser = require("../browser"); var _browserContext = require("../browserContext"); var network = _interopRequireWildcard(require("../network")); var _bidiConnection = require("./bidiConnection"); var _bidiNetworkManager = require("./bidiNetworkManager"); var _bidiPage = require("./bidiPage"); var bidi = _interopRequireWildcard(require("./third_party/bidiProtocol")); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /** * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an 'AS IS' BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class BidiBrowser extends _browser.Browser { static async connect(parent, transport, options) { const browser = new BidiBrowser(parent, transport, options); if (options.__testHookOnConnectToBrowser) await options.__testHookOnConnectToBrowser(); let proxy; if (options.proxy) { proxy = { proxyType: 'manual' }; const url = new URL(options.proxy.server); // Validate proxy server. switch (url.protocol) { case 'http:': proxy.httpProxy = url.host; break; case 'https:': proxy.httpsProxy = 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: ' + options.proxy.server); } if (options.proxy.bypass) proxy.noProxy = options.proxy.bypass.split(','); // TODO: support authentication. } browser._bidiSessionInfo = await browser._browserSession.send('session.new', { capabilities: { alwaysMatch: { acceptInsecureCerts: false, proxy, unhandledPromptBehavior: { default: bidi.Session.UserPromptHandlerType.Ignore }, webSocketUrl: true } } }); await browser._browserSession.send('session.subscribe', { events: ['browsingContext', 'network', 'log', 'script'] }); if (options.persistent) { browser._defaultContext = new BidiBrowserContext(browser, undefined, options.persistent); await browser._defaultContext._initialize(); // Create default page as we cannot get access to the existing one. const pageDelegate = await browser._defaultContext.newPageDelegate(); await pageDelegate.pageOrError(); } return browser; } constructor(parent, transport, options) { super(parent, options); this._connection = void 0; this._browserSession = void 0; this._bidiSessionInfo = void 0; this._contexts = new Map(); this._bidiPages = new Map(); this._eventListeners = void 0; this._connection = new _bidiConnection.BidiConnection(transport, this._onDisconnect.bind(this), options.protocolLogger, options.browserLogsCollector); this._browserSession = this._connection.browserSession; this._eventListeners = [_eventsHelper.eventsHelper.addEventListener(this._browserSession, 'browsingContext.contextCreated', this._onBrowsingContextCreated.bind(this)), _eventsHelper.eventsHelper.addEventListener(this._browserSession, 'script.realmDestroyed', this._onScriptRealmDestroyed.bind(this))]; } _onDisconnect() { this._didClose(); } async doCreateNewContext(options) { const { userContext } = await this._browserSession.send('browser.createUserContext', {}); 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 page of this._bidiPages.values()) { const parentFrame = page._page._frameManager.frame(parentFrameId); if (!parentFrame) continue; page._session.addFrameBrowsingContext(event.context); page._page._frameManager.frameAttached(event.context, parentFrameId); 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 _bidiPage.BidiPage(context, session, opener || null); 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; } } } exports.BidiBrowser = BidiBrowser; class BidiBrowserContext extends _browserContext.BrowserContext { constructor(browser, browserContextId, options) { super(browser, options, browserContextId); this._authenticateProxyViaHeader(); } _bidiPages() { return [...this._browser._bidiPages.values()].filter(bidiPage => bidiPage._browserContext === this); } pages() { return this._bidiPages().map(bidiPage => bidiPage._initializedPage).filter(Boolean); } async newPageDelegate() { (0, _browserContext.assertBrowserContextIsNotOwned)(this); const { context } = await this._browser._browserSession.send('browsingContext.create', { type: bidi.BrowsingContext.CreateType.Window, userContext: this._browserContextId }); return this._browser._bidiPages.get(context); } async doGetCookies(urls) { const { cookies } = await this._browser._browserSession.send('storage.getCookies', { partition: { type: 'storageKey', userContext: this._browserContextId } }); return network.filterCookies(cookies.map(c => { var _c$expiry; const copy = { name: c.name, value: (0, _bidiNetworkManager.bidiBytesValueToString)(c.value), domain: c.domain, path: c.path, httpOnly: c.httpOnly, secure: c.secure, expires: (_c$expiry = c.expiry) !== null && _c$expiry !== void 0 ? _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 === undefined ? undefined : 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) {} async doClearPermissions() {} async setGeolocation(geolocation) {} async setExtraHTTPHeaders(headers) {} async setUserAgent(userAgent) {} async setOffline(offline) {} async doSetHTTPCredentials(httpCredentials) { this._options.httpCredentials = httpCredentials; for (const page of this.pages()) await page._delegate.updateHttpCredentials(); } async doAddInitScript(initScript) { await Promise.all(this.pages().map(page => page._delegate.addInitScript(initScript))); } async doRemoveNonInternalInitScripts() {} async doUpdateRequestInterception() {} onClosePersistent() {} async clearCache() {} async doClose(reason) { if (!this._browserContextId) { // Closing persistent context should close the browser. 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) {} } exports.BidiBrowserContext = BidiBrowserContext; 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; } let Network = exports.Network = void 0; (function (_Network) { let SameSite = /*#__PURE__*/function (SameSite) { SameSite["Strict"] = "strict"; SameSite["Lax"] = "lax"; SameSite["None"] = "none"; return SameSite; }({}); _Network.SameSite = SameSite; })(Network || (exports.Network = Network = {}));