selenium-with-fingerprints
Version:
A plugin that improves the stealth of the selenium library using fingerprints
114 lines (96 loc) • 3.5 kB
JavaScript
const { scripts, MAX_RESIZE_RETRIES } = require('browser-with-fingerprints/src/common');
/**
* Add an event listener for the browser's `close` event.
*
* @param {import('selenium-webdriver').WebDriver} target - The listener target.
* @param {(() => void)} listener - The event listener.
*
* @internal
*/
exports.onClose = (target, listener) => {
target.onQuit_ = new Proxy(target.onQuit_, {
apply: (fn, ctx, args) => (listener(), fn.apply(ctx, args)),
});
};
/**
* Modify the original browser methods and add additional hooks.
* Hooks will be called before the corresponding method completes.
*
* @param {import('selenium-webdriver').WebDriver} driver - The target browser instance.
*
* @internal
*/
exports.bindHooks = (driver, hooks = {}) => {
driver.switchTo = new Proxy(driver.switchTo, {
apply(fn, ctx) {
const target = fn.call(ctx);
target.newWindow = new Proxy(target.newWindow, {
async apply(fn, ctx, [type]) {
await fn.call(ctx, type);
if (type === 'window') {
await hooks.onPageCreated?.(driver);
}
},
});
return target;
},
});
driver.manage = new Proxy(driver.manage, {
apply(fn, ctx) {
const options = fn.call(ctx);
options.window = new Proxy(options.window, {
apply(fn, ctx) {
const window = fn.call(ctx);
window.setRect = new Proxy(window.setRect, {
apply: () => console.warn('Warning: setting the viewport size is not allowed (limited by fingerprint).'),
});
return window;
},
});
return options;
},
});
};
/**
* Set the browser viewport size.
*
* @param {import('selenium-webdriver').WebDriver}} driver - The target driver to set the viewport.
* @param {{width: number, height: number}} bounds - New viewport size.
*
* @internal
*/
exports.setViewport = async (driver, { diff, width = 0, height = 0 }) => {
const delta = diff ? { ...diff } : { width: 16, height: 88 };
const { windowId } = await driver.sendAndGetDevToolsCommand('Browser.getWindowForTarget');
for (let i = 0; i < MAX_RESIZE_RETRIES; ++i) {
const bounds = { width: width + delta.width, height: height + delta.height };
await Promise.all([
driver.sendDevToolsCommand('Browser.setWindowBounds', { bounds, windowId }),
waitForResize(driver),
]);
const viewport = await this.getViewport(driver);
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;
}
};
/**
* Get the browser viewport size.
*
* @param {import('selenium-webdriver').WebDriver} driver - The target driver to get the viewport.
* @returns {Promise<{width: number, height: number}>} - Promise which resolves to a browser viewport size.
*
* @internal
*/
exports.getViewport = (driver) => driver.executeScript(scripts.getViewport);
/**
* Wait for the browser to resize.
*
* @param {import('selenium-webdriver').WebDriver} driver - The target driver to to wait for the browser to resize.
*/
const waitForResize = (driver) => driver.executeScript(scripts.waitForResize);