Rename to hkt.sh
This commit is contained in:
136
node_modules/puppeteer-extra-plugin-stealth/evasions/iframe.contentWindow/index.js
generated
vendored
Normal file
136
node_modules/puppeteer-extra-plugin-stealth/evasions/iframe.contentWindow/index.js
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
'use strict'
|
||||
|
||||
const { PuppeteerExtraPlugin } = require('puppeteer-extra-plugin')
|
||||
|
||||
const withUtils = require('../_utils/withUtils')
|
||||
|
||||
/**
|
||||
* Fix for the HEADCHR_IFRAME detection (iframe.contentWindow.chrome), hopefully this time without breaking iframes.
|
||||
* Note: Only `srcdoc` powered iframes cause issues due to a chromium bug:
|
||||
*
|
||||
* https://github.com/puppeteer/puppeteer/issues/1106
|
||||
*/
|
||||
class Plugin extends PuppeteerExtraPlugin {
|
||||
constructor(opts = {}) {
|
||||
super(opts)
|
||||
}
|
||||
|
||||
get name() {
|
||||
return 'stealth/evasions/iframe.contentWindow'
|
||||
}
|
||||
|
||||
get requirements() {
|
||||
// Make sure `chrome.runtime` has ran, we use data defined by it (e.g. `window.chrome`)
|
||||
return new Set(['runLast'])
|
||||
}
|
||||
|
||||
async onPageCreated(page) {
|
||||
await withUtils(page).evaluateOnNewDocument((utils, opts) => {
|
||||
try {
|
||||
// Adds a contentWindow proxy to the provided iframe element
|
||||
const addContentWindowProxy = iframe => {
|
||||
const contentWindowProxy = {
|
||||
get(target, key) {
|
||||
// Now to the interesting part:
|
||||
// We actually make this thing behave like a regular iframe window,
|
||||
// by intercepting calls to e.g. `.self` and redirect it to the correct thing. :)
|
||||
// That makes it possible for these assertions to be correct:
|
||||
// iframe.contentWindow.self === window.top // must be false
|
||||
if (key === 'self') {
|
||||
return this
|
||||
}
|
||||
// iframe.contentWindow.frameElement === iframe // must be true
|
||||
if (key === 'frameElement') {
|
||||
return iframe
|
||||
}
|
||||
// Intercept iframe.contentWindow[0] to hide the property 0 added by the proxy.
|
||||
if (key === '0') {
|
||||
return undefined
|
||||
}
|
||||
return Reflect.get(target, key)
|
||||
}
|
||||
}
|
||||
|
||||
if (!iframe.contentWindow) {
|
||||
const proxy = new Proxy(window, contentWindowProxy)
|
||||
Object.defineProperty(iframe, 'contentWindow', {
|
||||
get() {
|
||||
return proxy
|
||||
},
|
||||
set(newValue) {
|
||||
return newValue // contentWindow is immutable
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Handles iframe element creation, augments `srcdoc` property so we can intercept further
|
||||
const handleIframeCreation = (target, thisArg, args) => {
|
||||
const iframe = target.apply(thisArg, args)
|
||||
|
||||
// We need to keep the originals around
|
||||
const _iframe = iframe
|
||||
const _srcdoc = _iframe.srcdoc
|
||||
|
||||
// Add hook for the srcdoc property
|
||||
// We need to be very surgical here to not break other iframes by accident
|
||||
Object.defineProperty(iframe, 'srcdoc', {
|
||||
configurable: true, // Important, so we can reset this later
|
||||
get: function() {
|
||||
return _srcdoc
|
||||
},
|
||||
set: function(newValue) {
|
||||
addContentWindowProxy(this)
|
||||
// Reset property, the hook is only needed once
|
||||
Object.defineProperty(iframe, 'srcdoc', {
|
||||
configurable: false,
|
||||
writable: false,
|
||||
value: _srcdoc
|
||||
})
|
||||
_iframe.srcdoc = newValue
|
||||
}
|
||||
})
|
||||
return iframe
|
||||
}
|
||||
|
||||
// Adds a hook to intercept iframe creation events
|
||||
const addIframeCreationSniffer = () => {
|
||||
/* global document */
|
||||
const createElementHandler = {
|
||||
// Make toString() native
|
||||
get(target, key) {
|
||||
return Reflect.get(target, key)
|
||||
},
|
||||
apply: function(target, thisArg, args) {
|
||||
const isIframe =
|
||||
args && args.length && `${args[0]}`.toLowerCase() === 'iframe'
|
||||
if (!isIframe) {
|
||||
// Everything as usual
|
||||
return target.apply(thisArg, args)
|
||||
} else {
|
||||
return handleIframeCreation(target, thisArg, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
// All this just due to iframes with srcdoc bug
|
||||
utils.replaceWithProxy(
|
||||
document,
|
||||
'createElement',
|
||||
createElementHandler
|
||||
)
|
||||
}
|
||||
|
||||
// Let's go
|
||||
addIframeCreationSniffer()
|
||||
} catch (err) {
|
||||
// console.warn(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function(pluginConfig) {
|
||||
return new Plugin(pluginConfig)
|
||||
}
|
||||
448
node_modules/puppeteer-extra-plugin-stealth/evasions/iframe.contentWindow/index.test.js
generated
vendored
Normal file
448
node_modules/puppeteer-extra-plugin-stealth/evasions/iframe.contentWindow/index.test.js
generated
vendored
Normal file
@@ -0,0 +1,448 @@
|
||||
const test = require('ava')
|
||||
|
||||
const {
|
||||
getVanillaFingerPrint,
|
||||
getStealthFingerPrint,
|
||||
dummyHTMLPath,
|
||||
vanillaPuppeteer,
|
||||
addExtra
|
||||
} = require('../../test/util')
|
||||
// const Plugin = require('.')
|
||||
// NOTE: We're using the full plugin for testing here as `iframe.contentWindow` uses data set by `chrome.runtime`
|
||||
const Plugin = require('puppeteer-extra-plugin-stealth')
|
||||
|
||||
// Fix CI issues with old versions
|
||||
const isOldPuppeteerVersion = () => {
|
||||
const version = process.env.PUPPETEER_VERSION
|
||||
const isOld = version && (version === '1.9.0' || version === '1.6.2')
|
||||
return isOld
|
||||
}
|
||||
|
||||
test('vanilla: will be undefined', async t => {
|
||||
const { iframeChrome } = await getVanillaFingerPrint()
|
||||
t.is(iframeChrome, 'undefined')
|
||||
})
|
||||
|
||||
test('stealth: will be object', async t => {
|
||||
const { iframeChrome } = await getStealthFingerPrint(Plugin)
|
||||
t.is(iframeChrome, 'object')
|
||||
})
|
||||
|
||||
test('stealth: will not break iframes', async t => {
|
||||
const browser = await addExtra(vanillaPuppeteer)
|
||||
.use(Plugin())
|
||||
.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
const testFuncReturnValue = 'TESTSTRING'
|
||||
await page.evaluate(returnValue => {
|
||||
const { document } = window // eslint-disable-line
|
||||
const body = document.querySelector('body')
|
||||
const iframe = document.createElement('iframe')
|
||||
body.srcdoc = 'foobar'
|
||||
body.appendChild(iframe)
|
||||
iframe.contentWindow.mySuperFunction = () => returnValue
|
||||
}, testFuncReturnValue)
|
||||
const realReturn = await page.evaluate(
|
||||
() => document.querySelector('iframe').contentWindow.mySuperFunction() // eslint-disable-line
|
||||
)
|
||||
await browser.close()
|
||||
|
||||
t.is(realReturn, 'TESTSTRING')
|
||||
})
|
||||
|
||||
test('vanilla: will not have contentWindow[0]', async t => {
|
||||
const browser = await vanillaPuppeteer.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
const zero = await page.evaluate(returnValue => {
|
||||
const { document } = window // eslint-disable-line
|
||||
const body = document.querySelector('body')
|
||||
const iframe = document.createElement('iframe')
|
||||
iframe.srcdoc = 'foobar'
|
||||
body.appendChild(iframe)
|
||||
return typeof iframe.contentWindow[0]
|
||||
})
|
||||
await browser.close()
|
||||
|
||||
t.is(zero, 'undefined')
|
||||
})
|
||||
|
||||
test('stealth: will not have contentWindow[0]', async t => {
|
||||
const browser = await addExtra(vanillaPuppeteer)
|
||||
.use(Plugin())
|
||||
.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
const zero = await page.evaluate(returnValue => {
|
||||
const { document } = window // eslint-disable-line
|
||||
const body = document.querySelector('body')
|
||||
const iframe = document.createElement('iframe')
|
||||
iframe.srcdoc = 'foobar'
|
||||
body.appendChild(iframe)
|
||||
return typeof iframe.contentWindow[0]
|
||||
})
|
||||
await browser.close()
|
||||
|
||||
t.is(zero, 'undefined')
|
||||
})
|
||||
|
||||
test('vanilla: will not have chrome runtine in any frame', async t => {
|
||||
const browser = await vanillaPuppeteer.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
await page.goto('file://' + dummyHTMLPath)
|
||||
|
||||
const basiciframe = await page.evaluate(() => {
|
||||
const el = document.createElement('iframe')
|
||||
document.body.appendChild(el)
|
||||
return el.contentWindow.chrome
|
||||
})
|
||||
|
||||
const sandboxSOiframe = await page.evaluate(() => {
|
||||
const el = document.createElement('iframe')
|
||||
el.setAttribute('sandbox', 'allow-same-origin')
|
||||
document.body.appendChild(el)
|
||||
return el.contentWindow.chrome
|
||||
})
|
||||
|
||||
const sandboxSOASiframe = await page.evaluate(() => {
|
||||
const el = document.createElement('iframe')
|
||||
el.setAttribute('sandbox', 'allow-same-origin allow-scripts')
|
||||
document.body.appendChild(el)
|
||||
return el.contentWindow.chrome
|
||||
})
|
||||
|
||||
const srcdociframe = await page.evaluate(() => {
|
||||
const el = document.createElement('iframe')
|
||||
el.srcdoc = 'blank page, boys.'
|
||||
document.body.appendChild(el)
|
||||
return el.contentWindow.chrome
|
||||
})
|
||||
|
||||
// console.log('basic iframe', basiciframe)
|
||||
// console.log('sandbox same-origin iframe', sandboxSOiframe)
|
||||
// console.log('sandbox same-origin&scripts iframe', sandboxSOASiframe)
|
||||
// console.log('srcdoc iframe', srcdociframe)
|
||||
|
||||
await browser.close()
|
||||
|
||||
t.is(typeof basiciframe, 'undefined')
|
||||
t.is(typeof sandboxSOiframe, 'undefined')
|
||||
t.is(typeof sandboxSOASiframe, 'undefined')
|
||||
t.is(typeof srcdociframe, 'undefined')
|
||||
})
|
||||
|
||||
test('stealth: it will cover all frames including srcdoc', async t => {
|
||||
// const browser = await vanillaPuppeteer.launch({ headless: false })
|
||||
const browser = await addExtra(vanillaPuppeteer)
|
||||
.use(Plugin())
|
||||
.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
await page.goto('file://' + dummyHTMLPath)
|
||||
|
||||
const basiciframe = await page.evaluate(() => {
|
||||
const el = document.createElement('iframe')
|
||||
document.body.appendChild(el)
|
||||
return el.contentWindow.chrome
|
||||
})
|
||||
|
||||
const sandboxSOiframe = await page.evaluate(() => {
|
||||
const el = document.createElement('iframe')
|
||||
el.setAttribute('sandbox', 'allow-same-origin')
|
||||
document.body.appendChild(el)
|
||||
return el.contentWindow.chrome
|
||||
})
|
||||
|
||||
const sandboxSOASiframe = await page.evaluate(() => {
|
||||
const el = document.createElement('iframe')
|
||||
el.setAttribute('sandbox', 'allow-same-origin allow-scripts')
|
||||
document.body.appendChild(el)
|
||||
return el.contentWindow.chrome
|
||||
})
|
||||
|
||||
const srcdociframe = await page.evaluate(() => {
|
||||
const el = document.createElement('iframe')
|
||||
el.srcdoc = 'blank page, boys.'
|
||||
document.body.appendChild(el)
|
||||
return el.contentWindow.chrome
|
||||
})
|
||||
|
||||
// console.log('basic iframe', basiciframe)
|
||||
// console.log('sandbox same-origin iframe', sandboxSOiframe)
|
||||
// console.log('sandbox same-origin&scripts iframe', sandboxSOASiframe)
|
||||
// console.log('srcdoc iframe', srcdociframe)
|
||||
|
||||
await browser.close()
|
||||
|
||||
if (isOldPuppeteerVersion()) {
|
||||
t.is(typeof basiciframe, 'object')
|
||||
} else {
|
||||
t.is(typeof basiciframe, 'object')
|
||||
t.is(typeof sandboxSOiframe, 'object')
|
||||
t.is(typeof sandboxSOASiframe, 'object')
|
||||
t.is(typeof srcdociframe, 'object')
|
||||
}
|
||||
})
|
||||
|
||||
test('vanilla: will allow to define property contentWindow', async t => {
|
||||
const browser = await vanillaPuppeteer.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
const iframe = await page.evaluate(() => {
|
||||
const { document } = window // eslint-disable-line
|
||||
const iframe = document.createElement('iframe')
|
||||
iframe.srcdoc = 'foobar'
|
||||
return Object.defineProperty(iframe, 'contentWindow', { value: 'baz' })
|
||||
})
|
||||
await browser.close()
|
||||
|
||||
t.is(typeof iframe, 'object')
|
||||
})
|
||||
|
||||
// test('stealth: will allow to define property contentWindow', async t => {
|
||||
// const browser = await addExtra(vanillaPuppeteer)
|
||||
// .use(Plugin())
|
||||
// .launch({ headless: true })
|
||||
// const page = await browser.newPage()
|
||||
|
||||
// const iframe = await page.evaluate(() => {
|
||||
// const { document } = window // eslint-disable-line
|
||||
// const iframe = document.createElement('iframe')
|
||||
// iframe.srcdoc = 'foobar'
|
||||
// return Object.defineProperty(iframe, 'contentWindow', { value: 'baz' })
|
||||
// })
|
||||
// await browser.close()
|
||||
|
||||
// t.is(typeof iframe, 'object')
|
||||
// })
|
||||
|
||||
test('vanilla: will return undefined for getOwnPropertyDescriptor of contentWindow', async t => {
|
||||
const browser = await vanillaPuppeteer.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
const iframe = await page.evaluate(() => {
|
||||
const { document } = window // eslint-disable-line
|
||||
const iframe = document.createElement('iframe')
|
||||
iframe.srcdoc = 'foobar'
|
||||
return Object.getOwnPropertyDescriptor(iframe, 'contentWindow')
|
||||
})
|
||||
await browser.close()
|
||||
|
||||
t.is(iframe, undefined)
|
||||
})
|
||||
|
||||
// test('stealth: will return undefined for getOwnPropertyDescriptor of contentWindow', async t => {
|
||||
// const browser = await addExtra(vanillaPuppeteer)
|
||||
// .use(Plugin())
|
||||
// .launch({ headless: true })
|
||||
// const page = await browser.newPage()
|
||||
|
||||
// const iframe = await page.evaluate(() => {
|
||||
// const { document } = window // eslint-disable-line
|
||||
// const iframe = document.createElement('iframe')
|
||||
// iframe.srcdoc = 'foobar'
|
||||
// return Object.getOwnPropertyDescriptor(iframe, 'contentWindow')
|
||||
// })
|
||||
// await browser.close()
|
||||
|
||||
// t.is(iframe, undefined)
|
||||
// })
|
||||
|
||||
/* global HTMLIFrameElement */
|
||||
test('stealth: it will emulate advanved contentWindow features correctly', async t => {
|
||||
// const browser = await vanillaPuppeteer.launch({ headless: false })
|
||||
const browser = await addExtra(vanillaPuppeteer)
|
||||
.use(Plugin())
|
||||
.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
await page.goto('file://' + dummyHTMLPath)
|
||||
|
||||
// page.on('console', msg => {
|
||||
// console.log('Page console: ', msg.text())
|
||||
// })
|
||||
|
||||
const results = await page.evaluate(() => {
|
||||
const results = {}
|
||||
|
||||
const iframe = document.createElement('iframe')
|
||||
iframe.srcdoc = 'page intentionally left blank' // Note: srcdoc
|
||||
document.body.appendChild(iframe)
|
||||
|
||||
const basicIframe = document.createElement('iframe')
|
||||
basicIframe.src = 'data:text/plain;charset=utf-8,foobar'
|
||||
document.body.appendChild(iframe)
|
||||
|
||||
results.descriptors = (() => {
|
||||
// Verify iframe prototype isn't touched
|
||||
const descriptors = Object.getOwnPropertyDescriptors(
|
||||
HTMLIFrameElement.prototype
|
||||
)
|
||||
return descriptors.contentWindow.get.toString()
|
||||
})()
|
||||
|
||||
results.noProxySignature = (() => {
|
||||
return iframe.srcdoc.toString.hasOwnProperty('[[IsRevoked]]') // eslint-disable-line
|
||||
})()
|
||||
|
||||
results.doesExist = (() => {
|
||||
// Verify iframe isn't remapped to main window
|
||||
return !!iframe.contentWindow
|
||||
})()
|
||||
|
||||
results.isNotAClone = (() => {
|
||||
// Verify iframe isn't remapped to main window
|
||||
return iframe.contentWindow !== window
|
||||
})()
|
||||
|
||||
results.hasPlugins = (() => {
|
||||
return iframe.contentWindow.navigator.plugins.length > 0
|
||||
})()
|
||||
|
||||
results.hasSameNumberOfPlugins = (() => {
|
||||
return (
|
||||
window.navigator.plugins.length ===
|
||||
iframe.contentWindow.navigator.plugins.length
|
||||
)
|
||||
})()
|
||||
|
||||
results.SelfIsNotWindow = (() => {
|
||||
return iframe.contentWindow.self !== window
|
||||
})()
|
||||
|
||||
results.SelfIsNotWindowTop = (() => {
|
||||
return iframe.contentWindow.self !== window.top
|
||||
})()
|
||||
|
||||
results.TopIsNotSame = (() => {
|
||||
return iframe.contentWindow.top !== iframe.contentWindow
|
||||
})()
|
||||
|
||||
results.FrameElementMatches = (() => {
|
||||
return iframe.contentWindow.frameElement === iframe
|
||||
})()
|
||||
|
||||
results.StackTraces = (() => {
|
||||
try {
|
||||
// eslint-disable-next-line
|
||||
document['createElement'](0)
|
||||
} catch (e) {
|
||||
return e.stack
|
||||
}
|
||||
return false
|
||||
})()
|
||||
|
||||
return results
|
||||
})
|
||||
|
||||
await browser.close()
|
||||
|
||||
if (isOldPuppeteerVersion()) {
|
||||
t.true(true)
|
||||
return
|
||||
}
|
||||
|
||||
t.is(results.descriptors, 'function get contentWindow() { [native code] }')
|
||||
t.true(results.doesExist)
|
||||
t.true(results.isNotAClone)
|
||||
t.true(results.hasPlugins)
|
||||
t.true(results.hasSameNumberOfPlugins)
|
||||
t.true(results.SelfIsNotWindow)
|
||||
t.true(results.SelfIsNotWindowTop)
|
||||
t.true(results.TopIsNotSame)
|
||||
t.false(results.StackTraces.includes(`at Object.apply`))
|
||||
})
|
||||
|
||||
test('regression: new method will not break hcaptcha', async t => {
|
||||
const browser = await addExtra(vanillaPuppeteer)
|
||||
.use(Plugin())
|
||||
.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
page.waitForTimeout = page.waitForTimeout || page.waitFor
|
||||
|
||||
await page.goto('https://democaptcha.com/demo-form-eng/hcaptcha.html', {
|
||||
waitUntil: 'networkidle2'
|
||||
})
|
||||
await page.evaluate(() => {
|
||||
window.hcaptcha.execute()
|
||||
})
|
||||
await page.waitForTimeout(2 * 1000)
|
||||
const { hasChallengePopup } = await page.evaluate(() => {
|
||||
const hasChallengePopup = !!document.querySelectorAll(
|
||||
`div[style*='visible'] iframe[title*='hCaptcha challenge']`
|
||||
).length
|
||||
return { hasChallengePopup }
|
||||
})
|
||||
await browser.close()
|
||||
t.true(hasChallengePopup)
|
||||
})
|
||||
|
||||
test('regression: new method will not break recaptcha popup', async t => {
|
||||
// const browser = await vanillaPuppeteer.launch({ headless: false })
|
||||
const browser = await addExtra(vanillaPuppeteer)
|
||||
.use(Plugin())
|
||||
.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
page.waitForTimeout = page.waitForTimeout || page.waitFor
|
||||
|
||||
await page.goto('https://www.fbdemo.com/invisible-captcha/index.html', {
|
||||
waitUntil: 'networkidle2'
|
||||
})
|
||||
|
||||
await page.type('#tswname', 'foo')
|
||||
await page.type('#tswemail', 'foo@foo.foo')
|
||||
await page.type(
|
||||
'#tswcomments',
|
||||
'In the depth of winter, I finally learned that within me there lay an invincible summer.'
|
||||
)
|
||||
await page.click('#tswsubmit')
|
||||
await page.waitForTimeout(1000)
|
||||
const { hasRecaptchaPopup } = await page.evaluate(() => {
|
||||
const hasRecaptchaPopup = !!document.querySelectorAll(
|
||||
`iframe[title*="recaptcha challenge"]`
|
||||
).length
|
||||
return { hasRecaptchaPopup }
|
||||
})
|
||||
await browser.close()
|
||||
t.true(hasRecaptchaPopup)
|
||||
})
|
||||
|
||||
test('regression: old method indeed did break recaptcha popup', async t => {
|
||||
const browser = await vanillaPuppeteer.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
|
||||
page.waitForTimeout = page.waitForTimeout || page.waitFor
|
||||
// Old method
|
||||
await page.evaluateOnNewDocument(() => {
|
||||
// eslint-disable-next-line
|
||||
Object.defineProperty(HTMLIFrameElement.prototype, 'contentWindow', {
|
||||
get: function() {
|
||||
return window
|
||||
}
|
||||
})
|
||||
})
|
||||
await page.goto('https://www.fbdemo.com/invisible-captcha/index.html', {
|
||||
waitUntil: 'networkidle2'
|
||||
})
|
||||
await page.type('#tswname', 'foo')
|
||||
await page.type('#tswemail', 'foo@foo.foo')
|
||||
await page.type(
|
||||
'#tswcomments',
|
||||
'In the depth of winter, I finally learned that within me there lay an invincible summer.'
|
||||
)
|
||||
await page.click('#tswsubmit')
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
const { hasRecaptchaPopup } = await page.evaluate(() => {
|
||||
const hasRecaptchaPopup = !!document.querySelectorAll(
|
||||
`iframe[title*="recaptcha challenge"]`
|
||||
).length
|
||||
return { hasRecaptchaPopup }
|
||||
})
|
||||
await browser.close()
|
||||
t.false(hasRecaptchaPopup)
|
||||
})
|
||||
4
node_modules/puppeteer-extra-plugin-stealth/evasions/iframe.contentWindow/package.json
generated
vendored
Normal file
4
node_modules/puppeteer-extra-plugin-stealth/evasions/iframe.contentWindow/package.json
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"private": true,
|
||||
"main": "index.js"
|
||||
}
|
||||
20
node_modules/puppeteer-extra-plugin-stealth/evasions/iframe.contentWindow/readme.md
generated
vendored
Normal file
20
node_modules/puppeteer-extra-plugin-stealth/evasions/iframe.contentWindow/readme.md
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
## API
|
||||
|
||||
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
|
||||
|
||||
#### Table of Contents
|
||||
|
||||
- [class: Plugin](#class-plugin)
|
||||
|
||||
### class: [Plugin](https://github.com/berstend/puppeteer-extra/blob/e6133619b051febed630ada35241664eba59b9fa/packages/puppeteer-extra-plugin-stealth/evasions/iframe.contentWindow/index.js#L11-L125)
|
||||
|
||||
- `opts` (optional, default `{}`)
|
||||
|
||||
**Extends: PuppeteerExtraPlugin**
|
||||
|
||||
Fix for the HEADCHR_IFRAME detection (iframe.contentWindow.chrome), hopefully this time without breaking iframes.
|
||||
Note: Only `srcdoc` powered iframes cause issues due to a chromium bug:
|
||||
|
||||
<https://github.com/puppeteer/puppeteer/issues/1106>
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user