-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
using puppeteer-extra-plugin-stealth implementation in PHP
- Loading branch information
1 parent
3d1ebc6
commit 94c7ea5
Showing
21 changed files
with
1,809 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
2.6.0.5 | ||
2.6.1.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# NOTE | ||
This is a port of [puppeteer-extra-plugin-stealth](https://github.com/berstend/puppeteer-extra/blob/master/packages/puppeteer-extra-plugin-stealth) to PHP | ||
|
||
`navigator.webdriver` and `user-agent-override` are implemented using PHP code! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// https://github.com/berstend/puppeteer-extra/blob/master/packages/puppeteer-extra-plugin-stealth/evasions/chrome.app/index.js | ||
(function () { | ||
utils.init() | ||
if (!window.chrome) { | ||
// Use the exact property descriptor found in headful Chrome | ||
// fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')` | ||
Object.defineProperty(window, 'chrome', { | ||
writable: true, | ||
enumerable: true, | ||
configurable: false, // note! | ||
value: {} // We'll extend that later | ||
}) | ||
} | ||
|
||
// That means we're running headful and don't need to mock anything | ||
if ('app' in window.chrome) { | ||
return // Nothing to do here | ||
} | ||
|
||
const makeError = { | ||
ErrorInInvocation: fn => { | ||
const err = new TypeError(`Error in invocation of app.${fn}()`) | ||
return utils.stripErrorWithAnchor( | ||
err, | ||
`at ${fn} (eval at <anonymous>` | ||
) | ||
} | ||
} | ||
|
||
// There's a some static data in that property which doesn't seem to change, | ||
// we should periodically check for updates: `JSON.stringify(window.app, null, 2)` | ||
const STATIC_DATA = JSON.parse( | ||
` | ||
{ | ||
"isInstalled": false, | ||
"InstallState": { | ||
"DISABLED": "disabled", | ||
"INSTALLED": "installed", | ||
"NOT_INSTALLED": "not_installed" | ||
}, | ||
"RunningState": { | ||
"CANNOT_RUN": "cannot_run", | ||
"READY_TO_RUN": "ready_to_run", | ||
"RUNNING": "running" | ||
} | ||
} | ||
`.trim() | ||
) | ||
|
||
window.chrome.app = { | ||
...STATIC_DATA, | ||
|
||
get isInstalled() { | ||
return false | ||
}, | ||
|
||
getDetails: function getDetails() { | ||
if (arguments.length) { | ||
throw makeError.ErrorInInvocation(`getDetails`) | ||
} | ||
return null | ||
}, | ||
getIsInstalled: function getDetails() { | ||
if (arguments.length) { | ||
throw makeError.ErrorInInvocation(`getIsInstalled`) | ||
} | ||
return false | ||
}, | ||
runningState: function getDetails() { | ||
if (arguments.length) { | ||
throw makeError.ErrorInInvocation(`runningState`) | ||
} | ||
return 'cannot_run' | ||
} | ||
} | ||
utils.patchToStringNested(window.chrome.app) | ||
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// https://github.com/berstend/puppeteer-extra/blob/master/packages/puppeteer-extra-plugin-stealth/evasions/chrome.csi/index.js | ||
|
||
(function () { | ||
utils.init() | ||
if (!window.chrome) { | ||
// Use the exact property descriptor found in headful Chrome | ||
// fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')` | ||
Object.defineProperty(window, 'chrome', { | ||
writable: true, | ||
enumerable: true, | ||
configurable: false, // note! | ||
value: {} // We'll extend that later | ||
}) | ||
} | ||
|
||
// That means we're running headful and don't need to mock anything | ||
if ('csi' in window.chrome) { | ||
return // Nothing to do here | ||
} | ||
|
||
// Check that the Navigation Timing API v1 is available, we need that | ||
if (!window.performance || !window.performance.timing) { | ||
return | ||
} | ||
|
||
const { timing } = window.performance | ||
|
||
window.chrome.csi = function () { | ||
return { | ||
onloadT: timing.domContentLoadedEventEnd, | ||
startE: timing.navigationStart, | ||
pageT: Date.now() - timing.navigationStart, | ||
tran: 15 // Transition type or something | ||
} | ||
} | ||
utils.patchToString(window.chrome.csi) | ||
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// https://github.com/berstend/puppeteer-extra/blob/master/packages/puppeteer-extra-plugin-stealth/evasions/chrome.loadTimes/index.js | ||
|
||
(function () { | ||
utils.init() | ||
if (!window.chrome) { | ||
// Use the exact property descriptor found in headful Chrome | ||
// fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')` | ||
Object.defineProperty(window, 'chrome', { | ||
writable: true, | ||
enumerable: true, | ||
configurable: false, // note! | ||
value: {} // We'll extend that later | ||
}) | ||
} | ||
|
||
// That means we're running headful and don't need to mock anything | ||
if ('loadTimes' in window.chrome) { | ||
return // Nothing to do here | ||
} | ||
|
||
// Check that the Navigation Timing API v1 + v2 is available, we need that | ||
if ( | ||
!window.performance || | ||
!window.performance.timing || | ||
!window.PerformancePaintTiming | ||
) { | ||
return | ||
} | ||
|
||
const { performance } = window | ||
|
||
// Some stuff is not available on about:blank as it requires a navigation to occur, | ||
// let's harden the code to not fail then: | ||
const ntEntryFallback = { | ||
nextHopProtocol: 'h2', | ||
type: 'other' | ||
} | ||
|
||
// The API exposes some funky info regarding the connection | ||
const protocolInfo = { | ||
get connectionInfo() { | ||
const ntEntry = | ||
performance.getEntriesByType('navigation')[0] || ntEntryFallback | ||
return ntEntry.nextHopProtocol | ||
}, | ||
get npnNegotiatedProtocol() { | ||
// NPN is deprecated in favor of ALPN, but this implementation returns the | ||
// HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN. | ||
const ntEntry = | ||
performance.getEntriesByType('navigation')[0] || ntEntryFallback | ||
return ['h2', 'hq'].includes(ntEntry.nextHopProtocol) | ||
? ntEntry.nextHopProtocol | ||
: 'unknown' | ||
}, | ||
get navigationType() { | ||
const ntEntry = | ||
performance.getEntriesByType('navigation')[0] || ntEntryFallback | ||
return ntEntry.type | ||
}, | ||
get wasAlternateProtocolAvailable() { | ||
// The Alternate-Protocol header is deprecated in favor of Alt-Svc | ||
// (https://www.mnot.net/blog/2016/03/09/alt-svc), so technically this | ||
// should always return false. | ||
return false | ||
}, | ||
get wasFetchedViaSpdy() { | ||
// SPDY is deprecated in favor of HTTP/2, but this implementation returns | ||
// true for HTTP/2 or HTTP2+QUIC/39 as well. | ||
const ntEntry = | ||
performance.getEntriesByType('navigation')[0] || ntEntryFallback | ||
return ['h2', 'hq'].includes(ntEntry.nextHopProtocol) | ||
}, | ||
get wasNpnNegotiated() { | ||
// NPN is deprecated in favor of ALPN, but this implementation returns true | ||
// for HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN. | ||
const ntEntry = | ||
performance.getEntriesByType('navigation')[0] || ntEntryFallback | ||
return ['h2', 'hq'].includes(ntEntry.nextHopProtocol) | ||
} | ||
} | ||
|
||
const { timing } = window.performance | ||
|
||
// Truncate number to specific number of decimals, most of the `loadTimes` stuff has 3 | ||
function toFixed(num, fixed) { | ||
var re = new RegExp('^-?\\d+(?:.\\d{0,' + (fixed || -1) + '})?') | ||
return num.toString().match(re)[0] | ||
} | ||
|
||
const timingInfo = { | ||
get firstPaintAfterLoadTime() { | ||
// This was never actually implemented and always returns 0. | ||
return 0 | ||
}, | ||
get requestTime() { | ||
return timing.navigationStart / 1000 | ||
}, | ||
get startLoadTime() { | ||
return timing.navigationStart / 1000 | ||
}, | ||
get commitLoadTime() { | ||
return timing.responseStart / 1000 | ||
}, | ||
get finishDocumentLoadTime() { | ||
return timing.domContentLoadedEventEnd / 1000 | ||
}, | ||
get finishLoadTime() { | ||
return timing.loadEventEnd / 1000 | ||
}, | ||
get firstPaintTime() { | ||
const fpEntry = performance.getEntriesByType('paint')[0] || { | ||
startTime: timing.loadEventEnd / 1000 // Fallback if no navigation occured (`about:blank`) | ||
} | ||
return toFixed( | ||
(fpEntry.startTime + performance.timeOrigin) / 1000, | ||
3 | ||
) | ||
} | ||
} | ||
|
||
window.chrome.loadTimes = function () { | ||
return { | ||
...protocolInfo, | ||
...timingInfo | ||
} | ||
} | ||
utils.patchToString(window.chrome.loadTimes) | ||
})() |
Oops, something went wrong.