Skip to content

Commit

Permalink
Support service workers/shared workers (#401)
Browse files Browse the repository at this point in the history
* Added test for inconsistencies between page and service workers

* Wrong assert

* Added CreepJS test

* Fix plugin leak

* Add evaluateOnNewDocument() alias

* Use value instead of getter for navigator.hardwareConcurrency

* Use util functions for navigator.languages

* Nicer code in navigator.permissions

* Disable SW test

* Typo fix

* Fix tests

* Skip SW fixture in ava

* Add workflow matrix entry for pptr 5.5.0

* Revert cat & mouse test

* Add separate SW test (skipped for now)

* Disable 5.5.0 again
  • Loading branch information
Niek authored Jan 12, 2021
1 parent da2e953 commit 3281764
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

const { PuppeteerExtraPlugin } = require('puppeteer-extra-plugin')

const withUtils = require('../_utils/withUtils')

/**
* Set the hardwareConcurrency to 4 (optionally configurable with `hardwareConcurrency`)
*
Expand All @@ -23,15 +21,15 @@ class Plugin extends PuppeteerExtraPlugin {
}

async onPageCreated(page) {
await withUtils(page).evaluateOnNewDocument((utils, opts) => {
const patchNavigator = (name, value) =>
utils.replaceProperty(Object.getPrototypeOf(navigator), name, {
get() {
return value
}
})

patchNavigator('hardwareConcurrency', opts.hardwareConcurrency || 4)
await page.evaluateOnNewDocument(opts => {
Object.defineProperty(
Object.getPrototypeOf(navigator),
'hardwareConcurrency',
{
value: opts.hardwareConcurrency || 4,
writable: false
}
)
}, this.opts)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

const { PuppeteerExtraPlugin } = require('puppeteer-extra-plugin')
const withUtils = require('../_utils/withUtils')

/**
* Pass the Languages Test. Allows setting custom languages.
Expand All @@ -17,10 +18,10 @@ class Plugin extends PuppeteerExtraPlugin {
return 'stealth/evasions/navigator.languages'
}

// Overwrite the `languages` property to use a custom getter.
async onPageCreated(page) {
await page.evaluateOnNewDocument(opts => {
// Overwrite the `languages` property to use a custom getter.
Object.defineProperty(Object.getPrototypeOf(navigator), 'languages', {
await withUtils(page).evaluateOnNewDocument((utils, opts) => {
utils.replaceProperty(Object.getPrototypeOf(navigator), 'languages', {
get: () => opts.languages || ['en-US', 'en']
})
}, this.opts)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class Plugin extends PuppeteerExtraPlugin {
}

utils.replaceWithProxy(
window.navigator.permissions.__proto__, // eslint-disable-line no-proto
Object.getPrototypeOf(navigator.permissions),
'query',
handler
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ class Plugin extends PuppeteerExtraPlugin {
configurable: true
})
Object.defineProperty(mimeTypes[type], 'enabledPlugin', {
value: new Proxy(plugins[pluginData.name], {}), // Prevent circular references
value:
type === 'application/x-pnacl'
? mimeTypes['application/x-nacl'].enabledPlugin // these reference the same plugin, so we need to re-use the Proxy in order to avoid leaks
: new Proxy(plugins[pluginData.name], {}), // Prevent circular references
writable: false,
enumerable: false, // Important: `JSON.stringify(navigator.plugins)`
configurable: true
Expand Down
3 changes: 2 additions & 1 deletion packages/puppeteer-extra-plugin-stealth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
],
"ava": {
"files": [
"!test/util.js"
"!test/util.js",
"!test/fixtures/sw.js"
]
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Left empty
112 changes: 112 additions & 0 deletions packages/puppeteer-extra-plugin-stealth/test/service-worker.test.js
Original file line number Diff line number Diff line change
@@ -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
}
13 changes: 13 additions & 0 deletions packages/puppeteer-extra-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,10 @@ export abstract class PuppeteerExtraPlugin {
// noop
}

async onWorkerCreated(worker: Puppeteer.Worker) {
// noop
}

/**
* Called when the url of a target changes.
*
Expand Down Expand Up @@ -538,6 +542,15 @@ export abstract class PuppeteerExtraPlugin {
if (this.onPageCreated) {
await this.onPageCreated(page)
}
} else if (target.type() === 'service_worker' || target.type() === 'shared_worker') {
const worker = (await target.worker() as any)
if (worker) {
// Fixme: find some nicer way to add the method
worker.evaluateOnNewDocument = worker.evaluate
if (this.onWorkerCreated) {
await this.onWorkerCreated(worker)
}
}
}
}

Expand Down

0 comments on commit 3281764

Please sign in to comment.