browser-with-fingerprints
Version:
A plugin that improves the stealth of automation libraries using fingerprints
73 lines (64 loc) • 2.59 kB
JavaScript
const connect = require('chrome-remote-interface');
const { MAX_RESIZE_RETRIES } = require('../common');
/**
* Set the browser viewport size.
*
* @param {import('./launcher').Browser} browser - The target browser to set the viewport.
* @param {{width: number, height: number}} bounds - New viewport size.
*
* @internal
*/
exports.setViewport = async (browser, { diff, width, height }) => {
const cdp = await connect(browser);
const { windowId } = await cdp.Browser.getWindowForTarget();
const delta = diff ? { ...diff } : { width: 16, height: 88 };
for (let i = 0; i < MAX_RESIZE_RETRIES; ++i) {
const bounds = { width: width + delta.width, height: height + delta.height };
await Promise.all([cdp.Browser.setWindowBounds({ bounds, windowId }), waitForResize(cdp)]);
const viewport = await this.getViewport(cdp);
if (width === viewport.width && height === viewport.height) {
break;
} else if (i === MAX_RESIZE_RETRIES - 1) {
// TODO: improve handling of incorrect viewport size.
console.warn('Unable to set correct viewport size.');
}
delta.height += height - viewport.height;
delta.width += width - viewport.width;
}
await cdp.close();
};
/**
* Get the browser viewport size.
*
* @param {import('chrome-remote-interface').Client} cdp - The target client to get the viewport.
* @returns {Promise<{width: number, height: number}>} - Promise which resolves to a browser viewport size.
*
* @internal
*/
exports.getViewport = async (cdp) => {
const { result } = await cdp.Runtime.evaluate({
expression: `({ height: window.innerHeight, width: window.innerWidth })`,
returnByValue: true,
});
return result.value;
};
/**
* Wait for the browser to resize.
*
* In some cases, when the browser is in visible mode, resizing can take some time.
* In order not to use hardcoded values, we need to wait for the page to resize.
* The `ResizeObserver` in conjunction with `requestAnimationFrame` is convenient in that we don't need to use the `setTimeout` method.
*
* @param {import('chrome-remote-interface').Client} cdp - The target client to wait for the browser to resize.
*/
const waitForResize = async (cdp) => {
await cdp.Runtime.evaluate({
expression: `new Promise((done) => {
new ResizeObserver((_, observer) => {
requestAnimationFrame(() => requestAnimationFrame(() => done(observer.disconnect())));
}).observe(document.body);
})`,
returnByValue: true,
awaitPromise: true,
});
};