Rename to hkt.sh
This commit is contained in:
162
node_modules/puppeteer-extra-plugin-stealth/test/cat-and-mouse.test.js
generated
vendored
Normal file
162
node_modules/puppeteer-extra-plugin-stealth/test/cat-and-mouse.test.js
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
const test = require('ava')
|
||||
|
||||
const { vanillaPuppeteer, addExtra, compareLooseVersionStrings } = require('./util')
|
||||
const Plugin = require('..')
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
/* global HTMLIFrameElement */
|
||||
/* global Notification */
|
||||
test('stealth: will pass Paul Irish', async t => {
|
||||
const browser = await addExtra(vanillaPuppeteer)
|
||||
.use(Plugin())
|
||||
.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
await page.exposeFunction('compareLooseVersionStrings', compareLooseVersionStrings)
|
||||
const detectionResults = await page.evaluate(detectHeadless)
|
||||
await browser.close()
|
||||
|
||||
if (isOldPuppeteerVersion()) {
|
||||
t.true(true)
|
||||
return
|
||||
}
|
||||
|
||||
const wasHeadlessDetected = Object.values(detectionResults).some(Boolean)
|
||||
if (wasHeadlessDetected) {
|
||||
console.log(detectionResults)
|
||||
}
|
||||
t.false(wasHeadlessDetected)
|
||||
})
|
||||
|
||||
async function detectHeadless() {
|
||||
const results = {}
|
||||
|
||||
async function test(name, fn) {
|
||||
const detectionPassed = await fn()
|
||||
if (detectionPassed) console.log(`Chrome headless detected via ${name}`)
|
||||
results[name] = detectionPassed
|
||||
}
|
||||
|
||||
await test('userAgent', _ => {
|
||||
return /HeadlessChrome/.test(window.navigator.userAgent)
|
||||
})
|
||||
|
||||
// navigator.webdriver behavior change since release 89.0.4339.0. See also #448
|
||||
if (await compareLooseVersionStrings(navigator.userAgent, '89.0.4339.0') >= 0) {
|
||||
await test('navigator.webdriver is not false', _ => {
|
||||
return navigator.webdriver !== false
|
||||
})
|
||||
} else {
|
||||
// Detects the --enable-automation || --headless flags
|
||||
// Will return true in headful if --enable-automation is provided
|
||||
await test('navigator.webdriver present', _ => {
|
||||
return 'webdriver' in navigator
|
||||
})
|
||||
|
||||
await test('navigator.webdriver not undefined', _ => {
|
||||
return navigator.webdriver !== undefined
|
||||
})
|
||||
|
||||
/* eslint-disable no-proto */
|
||||
await test('navigator.webdriver property overridden', _ => {
|
||||
return (
|
||||
Object.getOwnPropertyDescriptor(navigator.__proto__, 'webdriver') !==
|
||||
undefined
|
||||
)
|
||||
})
|
||||
|
||||
await test('navigator.webdriver prop detected', _ => {
|
||||
for (const prop in navigator) {
|
||||
if (prop === 'webdriver') {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
await test('window.chrome missing', _ => {
|
||||
return /Chrome/.test(window.navigator.userAgent) && !window.chrome
|
||||
})
|
||||
|
||||
await test('permissions API', async _ => {
|
||||
const permissionStatus = await navigator.permissions.query({
|
||||
name: 'notifications'
|
||||
})
|
||||
return (
|
||||
Notification.permission === 'denied' &&
|
||||
permissionStatus.state === 'prompt'
|
||||
)
|
||||
})
|
||||
|
||||
await test('permissions API overriden', _ => {
|
||||
const permissions = window.navigator.permissions
|
||||
if (permissions.query.toString() !== 'function query() { [native code] }')
|
||||
return true
|
||||
if (
|
||||
permissions.query.toString.toString() !==
|
||||
'function toString() { [native code] }'
|
||||
)
|
||||
return true
|
||||
if (
|
||||
permissions.query.toString.hasOwnProperty('[[Handler]]') && // eslint-disable-line
|
||||
permissions.query.toString.hasOwnProperty('[[Target]]') && // eslint-disable-line
|
||||
permissions.query.toString.hasOwnProperty('[[IsRevoked]]') // eslint-disable-line
|
||||
)
|
||||
return true
|
||||
if (permissions.hasOwnProperty('query')) return true // eslint-disable-line
|
||||
})
|
||||
|
||||
await test('navigator.plugins empty', _ => {
|
||||
return navigator.plugins.length === 0
|
||||
})
|
||||
|
||||
await test('navigator.languages blank', _ => {
|
||||
return navigator.languages === ''
|
||||
})
|
||||
|
||||
await test('iFrame for fresh window object', _ => {
|
||||
// evaluateOnNewDocument scripts don't apply within [srcdoc] (or [sandbox]) iframes
|
||||
// https://github.com/GoogleChrome/puppeteer/issues/1106#issuecomment-359313898
|
||||
const iframe = document.createElement('iframe')
|
||||
iframe.srcdoc = 'page intentionally left blank'
|
||||
document.body.appendChild(iframe)
|
||||
|
||||
// Verify iframe prototype isn't touched
|
||||
const descriptors = Object.getOwnPropertyDescriptors(
|
||||
HTMLIFrameElement.prototype
|
||||
)
|
||||
|
||||
if (
|
||||
descriptors.contentWindow.get.toString() !==
|
||||
'function get contentWindow() { [native code] }'
|
||||
)
|
||||
return true
|
||||
// Verify iframe isn't remapped to main window
|
||||
if (iframe.contentWindow === window) return true
|
||||
|
||||
// Here we would need to rerun all tests with `iframe.contentWindow` as `window`
|
||||
// Example:
|
||||
return iframe.contentWindow.navigator.plugins.length === 0
|
||||
})
|
||||
|
||||
// This detects that a devtools protocol agent is attached.
|
||||
// So it will also pass true in headful Chrome if the devtools window is attached
|
||||
await test('toString', _ => {
|
||||
let gotYou = 0
|
||||
const spooky = /./
|
||||
spooky.toString = function() {
|
||||
gotYou++
|
||||
return 'spooky'
|
||||
}
|
||||
console.debug(spooky)
|
||||
return gotYou > 1
|
||||
})
|
||||
|
||||
return results
|
||||
}
|
||||
22
node_modules/puppeteer-extra-plugin-stealth/test/fixtures/dummy-with-service-worker.html
generated
vendored
Normal file
22
node_modules/puppeteer-extra-plugin-stealth/test/fixtures/dummy-with-service-worker.html
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>title foo</title>
|
||||
<!-- Testing evasions with a real html page makes things easier -->
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', function() {
|
||||
navigator.serviceWorker.register('/sw.js').then(function(registration) {
|
||||
console.log('ServiceWorker registration successful with scope: ', registration.scope);
|
||||
}, function(err) {
|
||||
console.log('ServiceWorker registration failed: ', err);
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test page with service worker</h1>
|
||||
</body>
|
||||
</html>
|
||||
11
node_modules/puppeteer-extra-plugin-stealth/test/fixtures/dummy.html
generated
vendored
Normal file
11
node_modules/puppeteer-extra-plugin-stealth/test/fixtures/dummy.html
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>title foo</title>
|
||||
<!-- Testing evasions with a real html page makes things easier -->
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test page</h1>
|
||||
</body>
|
||||
</html>
|
||||
1
node_modules/puppeteer-extra-plugin-stealth/test/fixtures/sw.js
generated
vendored
Normal file
1
node_modules/puppeteer-extra-plugin-stealth/test/fixtures/sw.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
// Left empty
|
||||
52
node_modules/puppeteer-extra-plugin-stealth/test/fpscanner.test.js
generated
vendored
Normal file
52
node_modules/puppeteer-extra-plugin-stealth/test/fpscanner.test.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
const test = require('ava')
|
||||
|
||||
const fpscanner = require('fpscanner')
|
||||
|
||||
const { getVanillaFingerPrint, getStealthFingerPrint, compareLooseVersionStrings } = require('./util')
|
||||
const Plugin = require('../.')
|
||||
|
||||
// Fix CI issues with old versions
|
||||
const isOldPuppeteerVersion = () => {
|
||||
const version = process.env.PUPPETEER_VERSION
|
||||
if (!version) {
|
||||
return false
|
||||
}
|
||||
if (version === '1.9.0' || version === '1.6.2') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
test('vanilla: will fail multiple fpscanner tests', async t => {
|
||||
const fingerPrint = await getVanillaFingerPrint()
|
||||
const testedFingerPrints = fpscanner.analyseFingerprint(fingerPrint)
|
||||
const failedChecks = Object.values(testedFingerPrints).filter(
|
||||
val => val.consistent < 3
|
||||
)
|
||||
|
||||
if (isOldPuppeteerVersion()) {
|
||||
t.is(failedChecks.length, 8)
|
||||
} else {
|
||||
t.is(failedChecks.length, 7)
|
||||
}
|
||||
})
|
||||
|
||||
test('stealth: will not fail a single fpscanner test', async t => {
|
||||
const fingerPrint = await getStealthFingerPrint(Plugin)
|
||||
const testedFingerPrints = fpscanner.analyseFingerprint(fingerPrint)
|
||||
const failedChecks = Object.values(testedFingerPrints).filter(
|
||||
val => val.consistent < 3
|
||||
)
|
||||
|
||||
if (failedChecks.length) {
|
||||
console.warn('The following fingerprints failed:', failedChecks)
|
||||
}
|
||||
|
||||
if (compareLooseVersionStrings(fingerPrint.userAgent, '89.0.4339.0') >= 0) {
|
||||
// Updated navigator.webdriver behavior breaks the fpscanner tests.
|
||||
t.is(failedChecks.length, 1)
|
||||
t.is(failedChecks[0].name, 'WEBDRIVER')
|
||||
} else {
|
||||
t.is(failedChecks.length, 0)
|
||||
}
|
||||
})
|
||||
112
node_modules/puppeteer-extra-plugin-stealth/test/service-worker.test.js
generated
vendored
Normal file
112
node_modules/puppeteer-extra-plugin-stealth/test/service-worker.test.js
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
const test = require('ava')
|
||||
|
||||
const { vanillaPuppeteer, addExtra } = require('./util')
|
||||
const Plugin = require('..')
|
||||
const http = require('http')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
// Create a simple HTTP server. Service Workers cannot be served from file:// URIs
|
||||
const httpServer = async () => {
|
||||
const server = await http
|
||||
.createServer((req, res) => {
|
||||
let contents, type
|
||||
|
||||
if (req.url === '/sw.js') {
|
||||
contents = fs.readFileSync(path.join(__dirname, './fixtures/sw.js'))
|
||||
type = 'application/javascript'
|
||||
} else {
|
||||
contents = fs.readFileSync(
|
||||
path.join(__dirname, './fixtures/dummy-with-service-worker.html')
|
||||
)
|
||||
type = 'text/html'
|
||||
}
|
||||
|
||||
res.setHeader('Content-Type', type)
|
||||
res.writeHead(200)
|
||||
res.end(contents)
|
||||
})
|
||||
.listen(0) // random free port
|
||||
|
||||
return `http://127.0.0.1:${server.address().port}/`
|
||||
}
|
||||
|
||||
let browser, page, worker
|
||||
|
||||
test.before(async t => {
|
||||
const address = await httpServer()
|
||||
console.log(`Server is running on port ${address}`)
|
||||
|
||||
browser = await addExtra(vanillaPuppeteer)
|
||||
.use(Plugin())
|
||||
.launch({ headless: true })
|
||||
page = await browser.newPage()
|
||||
|
||||
worker = new Promise(resolve => {
|
||||
browser.on('targetcreated', async target => {
|
||||
if (target.type() === 'service_worker') {
|
||||
resolve(target.worker())
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
await page.goto(address)
|
||||
worker = await worker
|
||||
})
|
||||
|
||||
test.after(async t => {
|
||||
await browser.close()
|
||||
})
|
||||
|
||||
test.skip('stealth: inconsistencies between page and worker', async t => {
|
||||
const pageFP = await page.evaluate(detectFingerprint)
|
||||
const workerFP = await worker.evaluate(detectFingerprint)
|
||||
|
||||
t.deepEqual(pageFP, workerFP)
|
||||
})
|
||||
|
||||
test.serial.skip('stealth: creepjs has good trust score', async t => {
|
||||
page.goto('https://abrahamjuliot.github.io/creepjs/')
|
||||
|
||||
const score = await (
|
||||
await (
|
||||
await page.waitForSelector('#fingerprint-data .unblurred')
|
||||
).getProperty('textContent')
|
||||
).jsonValue()
|
||||
|
||||
t.true(
|
||||
parseInt(score) > 80,
|
||||
`The creepjs score is: ${parseInt(score)}% but it should be at least 80%`
|
||||
)
|
||||
})
|
||||
|
||||
/* global OffscreenCanvas */
|
||||
function detectFingerprint() {
|
||||
const results = {}
|
||||
|
||||
const props = [
|
||||
'userAgent',
|
||||
'language',
|
||||
'hardwareConcurrency',
|
||||
'deviceMemory',
|
||||
'languages',
|
||||
'platform'
|
||||
]
|
||||
props.forEach(el => {
|
||||
results[el] = navigator[el].toString()
|
||||
})
|
||||
|
||||
const canvasOffscreenWebgl = new OffscreenCanvas(256, 256)
|
||||
const contextWebgl = canvasOffscreenWebgl.getContext('webgl')
|
||||
const rendererInfo = contextWebgl.getExtension('WEBGL_debug_renderer_info')
|
||||
results.webglVendor = contextWebgl.getParameter(
|
||||
rendererInfo.UNMASKED_VENDOR_WEBGL
|
||||
)
|
||||
results.webglRenderer = contextWebgl.getParameter(
|
||||
rendererInfo.UNMASKED_RENDERER_WEBGL
|
||||
)
|
||||
|
||||
results.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
|
||||
return results
|
||||
}
|
||||
65
node_modules/puppeteer-extra-plugin-stealth/test/util.js
generated
vendored
Normal file
65
node_modules/puppeteer-extra-plugin-stealth/test/util.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
const assert = require('assert')
|
||||
const vanillaPuppeteer = require('puppeteer')
|
||||
const { addExtra } = require('puppeteer-extra')
|
||||
|
||||
const fpCollectPath = require.resolve('fpcollect/dist/fpCollect.min.js')
|
||||
|
||||
const getFingerPrintFromPage = async page => {
|
||||
return page.evaluate(() => fpCollect.generateFingerprint()) // eslint-disable-line
|
||||
}
|
||||
|
||||
const dummyHTMLPath = require('path').join(__dirname, './fixtures/dummy.html')
|
||||
|
||||
const getFingerPrint = async (puppeteer, pageFn) => {
|
||||
const browser = await puppeteer.launch({ headless: true })
|
||||
const page = await browser.newPage()
|
||||
await page.goto('file://' + dummyHTMLPath)
|
||||
await page.addScriptTag({ path: fpCollectPath })
|
||||
const fingerPrint = await getFingerPrintFromPage(page)
|
||||
|
||||
let pageFnResult = null
|
||||
if (pageFn) {
|
||||
pageFnResult = await pageFn(page)
|
||||
}
|
||||
|
||||
await browser.close()
|
||||
return { ...fingerPrint, pageFnResult }
|
||||
}
|
||||
|
||||
const getVanillaFingerPrint = async pageFn =>
|
||||
getFingerPrint(vanillaPuppeteer, pageFn)
|
||||
const getStealthFingerPrint = async (Plugin, pageFn, pluginOptions = null) =>
|
||||
getFingerPrint(addExtra(vanillaPuppeteer).use(Plugin(pluginOptions)), pageFn)
|
||||
|
||||
// Expecting the input string to be in one of these formats:
|
||||
// - The UA string
|
||||
// - The shorter version string from Puppeteers browser.version()
|
||||
// - The shortest four-integer string
|
||||
const parseLooseVersionString = looseVersionString => looseVersionString
|
||||
.match(/(\d+\.){3}\d+/)[0]
|
||||
.split('.')
|
||||
.map(x => parseInt(x))
|
||||
|
||||
const compareLooseVersionStrings = (version0, version1) => {
|
||||
const parsed0 = parseLooseVersionString(version0)
|
||||
const parsed1 = parseLooseVersionString(version1)
|
||||
assert(parsed0.length == 4)
|
||||
assert(parsed1.length == 4)
|
||||
for (let i = 0; i < parsed0.length; i++) {
|
||||
if (parsed0[i] < parsed1[i]) {
|
||||
return -1
|
||||
} else if (parsed0[i] > parsed1[i]) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getVanillaFingerPrint,
|
||||
getStealthFingerPrint,
|
||||
dummyHTMLPath,
|
||||
vanillaPuppeteer,
|
||||
addExtra,
|
||||
compareLooseVersionStrings
|
||||
}
|
||||
Reference in New Issue
Block a user