fakebrowser
Version:
🤖 Fake fingerprints to bypass anti-bot systems. Simulate mouse and keyboard operations to make behavior like a real person.
396 lines • 31.8 kB
JavaScript
// noinspection JSUnusedGlobalSymbols,JSUnusedLocalSymbols,PointlessArithmeticExpressionJS
import { strict as assert } from 'assert';
import { helper } from './helper';
import { PptrToolkit } from './PptrToolkit';
export class FakeUserAction {
constructor(fb) {
this._mouseCurrPos = { x: helper.rd(0, 1280), y: helper.rd(0, 700) };
// this._fakeBrowser = new WeakRef<FakeBrowser>(fb)
this._fakeBrowser = fb;
}
/**
* Fake mouse movement track
* @param startPos
* @param endPos
* @param maxPoints
* @param cpDelta
*/
static mouseMovementTrack(startPos, endPos, maxPoints = 30, cpDelta = 1) {
// reference: https://github.com/mtsee/Bezier/blob/master/src/bezier.js
let nums = [];
let maxNum = 0;
let moveStep = 1;
// Simulates the user's mouse movement acceleration / constant speed / deceleration
for (let n = 0; n < maxPoints; ++n) {
nums.push(maxNum);
// noinspection PointlessArithmeticExpressionJS
if (n < maxPoints * 1 / 10) {
moveStep += helper.rd(60, 100);
}
else if (n >= maxPoints * 9 / 10) {
moveStep -= helper.rd(60, 100);
moveStep = Math.max(20, moveStep);
}
maxNum += moveStep;
}
const result = [];
const p1 = [
startPos.x,
startPos.y,
];
const cp1 = [
(startPos.x + endPos.x) / 2 + helper.rd(30, 100, true) * cpDelta,
(startPos.y + endPos.y) / 2 + helper.rd(30, 100, true) * cpDelta,
];
const cp2 = [
(startPos.x + endPos.x) / 2 + helper.rd(30, 100, true) * cpDelta,
(startPos.y + endPos.y) / 2 + helper.rd(30, 100, true) * cpDelta,
];
const p2 = [
endPos.x,
endPos.y,
];
for (let num of nums) {
const [x, y] = helper.threeBezier(num / maxNum, p1, cp1, cp2, p2);
result.push({ x, y });
}
return result;
}
/**
* Simulate mouse movement
* @param page
* @param options
*/
static async simMouseMove(page, options) {
const points = this.mouseMovementTrack(options.startPos, options.endPos, options.maxPoints || helper.rd(15, 30), options.cpDelta || 1);
for (let n = 0; n < points.length; n += 1) {
const point = points[n];
await page.mouse.move(point.x, point.y, { steps: helper.rd(1, 2) });
await helper.sleep((options.timestamp || helper.rd(300, 800)) / points.length);
}
}
get fakeBrowser() {
// @ts-ignore
if (!this._fakeBrowser || this._fakeBrowser._zombie) {
return null;
}
// WeakRef:
// const fb: FakeBrowser | undefined = this._fakeBrowser.deref()
const fb = this._fakeBrowser;
if (!fb) {
this._fakeBrowser = null;
return null;
}
return fb;
}
async simMouseMoveTo(endPos, maxPoints, timestamp, cpDelta) {
const fb = this.fakeBrowser;
if (!fb) {
return false;
}
if (fb.isMobileBrowser) {
// We don't need to simulate mouse slide.
await helper.sleepRd(300, 800);
return true;
}
// Get the current page of the browser
const currPage = await fb.getActivePage();
assert(currPage);
// first move to a close position, then finally move to the target position
const closeToEndPos = {
x: endPos.x + helper.rd(5, 30, true),
y: endPos.y + helper.rd(5, 20, true),
};
await FakeUserAction.simMouseMove(currPage, {
startPos: this._mouseCurrPos,
endPos: closeToEndPos,
maxPoints,
timestamp,
cpDelta,
});
// The last pos must correction
await currPage.mouse.move(endPos.x, endPos.y, { steps: helper.rd(5, 13) });
this._mouseCurrPos = endPos;
return true;
}
async simRandomMouseMove() {
const fb = this.fakeBrowser;
if (!fb) {
return false;
}
if (fb.isMobileBrowser) {
// We don't need to simulate mouse slide.
await helper.sleepRd(200, 500);
return true;
}
const fakeDD = fb.driverParams.fakeDeviceDesc;
assert(fakeDD);
const innerWidth = fakeDD.window.innerWidth;
const innerHeight = fakeDD.window.innerHeight;
// -----------------
// | 1/6 |
// | 1/4 1/4 |
// | 1/6 |
// -----------------
const startX = innerWidth / 4;
const startY = innerHeight / 6;
const endX = innerWidth * 3 / 4;
const endY = innerHeight * 5 / 6;
const endPos = { x: helper.rd(startX, endX), y: helper.rd(startY, endY) };
await this.simMouseMoveTo(endPos);
await helper.sleepRd(300, 800);
return true;
}
async simClick(options = {
pauseAfterMouseUp: true,
}) {
const fb = this.fakeBrowser;
if (!fb) {
return false;
}
const currPage = await fb.getActivePage();
assert(currPage);
if (fb.isMobileBrowser) {
// We can't use mouse obj, we have to use touchscreen
await currPage.touchscreen.tap(this._mouseCurrPos.x, this._mouseCurrPos.y);
}
else {
await currPage.mouse.down();
await helper.sleepRd(30, 80);
await currPage.mouse.up();
}
if (options && options.pauseAfterMouseUp) {
await helper.sleepRd(150, 600);
}
return true;
}
async simMoveToAndClick(endPos, options = {
pauseAfterMouseUp: true,
}) {
const fb = this.fakeBrowser;
if (!fb) {
return false;
}
const currPage = await fb.getActivePage();
assert(currPage);
if (!fb.isMobileBrowser) {
await this.simMouseMoveTo(endPos);
await currPage.mouse.move(endPos.x + helper.rd(-10, 10), endPos.y, { steps: helper.rd(8, 20) });
}
this._mouseCurrPos = endPos;
await helper.sleepRd(300, 800);
return this.simClick(options);
}
async simMouseMoveToElement(eh) {
const fb = this.fakeBrowser;
if (!fb) {
return false;
}
const fakeDD = fb.driverParams.fakeDeviceDesc;
assert(fakeDD);
const currPage = await fb.getActivePage();
assert(currPage);
let box;
if (fb.isMobileBrowser) {
box = await FakeUserAction.adjustElementPositionWithTouchscreen(eh, currPage, fakeDD);
}
else {
box = await FakeUserAction.adjustElementPositionWithMouse(eh, currPage, fakeDD);
}
if (box) {
// The position of each element click should not be the center of the element
// size of the clicked element must larger than 10 x 10
const endPos = {
x: box.x + box.width / 2 + helper.rd(0, 5, true),
y: box.y + box.height / 2 + helper.rd(0, 5, true),
};
await this.simMouseMoveTo(endPos);
// Pause
await helper.sleepRd(300, 800);
return true;
}
return false;
}
async simClickElement(eh, options = {
pauseAfterMouseUp: true,
}) {
const moveToEl = await this.simMouseMoveToElement(eh);
if (!moveToEl) {
return false;
}
// click
if (await this.simClick(options)) {
return true;
}
else {
return false;
}
}
static async adjustElementPositionWithMouse(eh, currPage, fakeDD) {
let box = null;
for (;;) {
box = await PptrToolkit.boundingBox(eh);
if (box) {
// Check the node is in the visible area
// @ts-ignore
let deltaX = 0;
let deltaY = 0;
let viewportAdjust = false;
// If the top of the node is less than 0
if (box.y <= 0) {
// deltaY always positive
// ---------------------
// 30px |
// [ ] |
// .. Distance to be moved
// .. |
// .. |
// ---------------------body top
deltaY = Math.min(-(box.y - 30) - 0, helper.rd(150, 300));
deltaY = -deltaY;
viewportAdjust = true;
}
else if (box.y + box.height >= fakeDD.window.innerHeight) {
// If the bottom is beyond
deltaY = Math.min(box.y + box.height + 30 - fakeDD.window.innerHeight, helper.rd(150, 300));
viewportAdjust = true;
}
// if (box.x <= 0) {
// // If the top of the button is less than 0
// deltaX = Math.min(-box.x + 30, sh.rd(100, 400))
// deltaX = -deltaX
// viewportAdjust = true
// } else if (box.x + box.width >= fakeDD.window.innerWidth) {
// // If the bottom is beyond
// deltaX = Math.min(box.x + box.width - fakeDD.window.innerWidth + 30, sh.rd(100, 400))
// viewportAdjust = true
// }
if (viewportAdjust) {
// await currPage.mouse.wheel({deltaX})
await currPage.mouse.wheel({ deltaY });
await helper.sleepRd(100, 400);
}
else {
break;
}
}
else {
break;
}
}
return box;
}
static async adjustElementPositionWithTouchscreen(eh, currPage, fakeDD) {
let box = null;
for (;;) {
box = await PptrToolkit.boundingBox(eh);
if (box) {
// @ts-ignore
let deltaX = 0;
let deltaY = 0;
let viewportAdjust = false;
if (box.y <= 0) {
deltaY = Math.min(-box.y + 30, helper.rd(100, 300));
deltaY = -deltaY;
viewportAdjust = true;
}
else if (box.y + box.height >= fakeDD.window.innerHeight) {
deltaY = Math.min(box.y + box.height - fakeDD.window.innerHeight + 30, helper.rd(100, 300));
viewportAdjust = true;
}
if (viewportAdjust) {
// noinspection TypeScriptValidateTypes
const _patchTouchscreenDesc = Object.getOwnPropertyDescriptor(currPage, '_patchTouchscreen');
assert(_patchTouchscreenDesc);
const touchscreen = _patchTouchscreenDesc.value;
assert(touchscreen);
// if deltaY is negative, drop down, otherwise drop up
const startX = fakeDD.window.innerWidth / 2 + helper.rd(0, fakeDD.window.innerWidth / 6);
const endX = fakeDD.window.innerWidth / 2 + helper.rd(0, fakeDD.window.innerWidth / 6);
let startY;
let endY;
if (deltaY < 0) {
startY = helper.rd(0, fakeDD.window.innerHeight - (-deltaY));
endY = startY + deltaY;
}
else {
startY = helper.rd(deltaY, fakeDD.window.innerHeight);
endY = startY - deltaY;
}
await touchscreen.drag({
x: startX, y: startY,
}, {
x: endX, y: endY,
});
await helper.sleepRd(100, 300);
}
else {
break;
}
}
else {
break;
}
}
return box;
}
async simKeyboardPress(text, options = {
pauseAfterKeyUp: true,
}) {
const fb = this.fakeBrowser;
if (!fb) {
return false;
}
const currPage = await fb.getActivePage();
assert(currPage);
await currPage.keyboard.press(text);
if (options && options.pauseAfterKeyUp) {
await helper.sleepRd(300, 1000);
}
return true;
}
async simKeyboardEnter(options = {
pauseAfterKeyUp: true,
}) {
return await this.simKeyboardPress('Enter', options);
}
async simKeyboardEsc(options = {
pauseAfterKeyUp: true,
}) {
return await this.simKeyboardPress('Escape', options);
}
async simKeyboardType(text, options = {
pauseAfterLastKeyUp: true,
}) {
const fb = this.fakeBrowser;
if (!fb) {
return false;
}
const currPage = await fb.getActivePage();
assert(currPage);
const needsShiftKey = '~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?';
// TODO: check if shiftKey, alt, ctrl can be fired in mobile browsers
for (let ch of text) {
let needsShift = false;
if (needsShiftKey.includes(ch)) {
needsShift = true;
await currPage.keyboard.down('ShiftLeft');
await helper.sleepRd(500, 1000);
}
// if a Chinese character
const isCh = ch.match(/^[\u4e00-\u9fa5]/);
const delay = isCh ? helper.rd(200, 800) : helper.rd(30, 100);
await currPage.keyboard.type('' + ch, { delay });
if (needsShift) {
await helper.sleepRd(150, 450);
await currPage.keyboard.up('ShiftLeft');
}
await helper.sleepRd(30, 100);
}
if (options && options.pauseAfterLastKeyUp) {
await helper.sleepRd(300, 1000);
}
return true;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmFrZVVzZXJBY3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29yZS9GYWtlVXNlckFjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwwRkFBMEY7QUFFMUYsT0FBTyxFQUFDLE1BQU0sSUFBSSxNQUFNLEVBQUMsTUFBTSxRQUFRLENBQUE7QUFJdkMsT0FBTyxFQUFDLE1BQU0sRUFBQyxNQUFNLFVBQVUsQ0FBQTtBQUUvQixPQUFPLEVBQUMsV0FBVyxFQUFDLE1BQU0sZUFBZSxDQUFBO0FBSXpDLE1BQU0sT0FBTyxjQUFjO0lBUXZCLFlBQVksRUFBZTtRQUN2QixJQUFJLENBQUMsYUFBYSxHQUFHLEVBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBQyxDQUFBO1FBQ2xFLG1EQUFtRDtRQUNuRCxJQUFJLENBQUMsWUFBWSxHQUFHLEVBQUUsQ0FBQTtJQUMxQixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ssTUFBTSxDQUFDLGtCQUFrQixDQUM3QixRQUFlLEVBQ2YsTUFBYSxFQUNiLFNBQVMsR0FBRyxFQUFFLEVBQ2QsT0FBTyxHQUFHLENBQUM7UUFFWCx1RUFBdUU7UUFFdkUsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFBO1FBQ2IsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFBO1FBQ2QsSUFBSSxRQUFRLEdBQUcsQ0FBQyxDQUFBO1FBRWhCLG1GQUFtRjtRQUNuRixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxFQUFFLEVBQUUsQ0FBQyxFQUFFO1lBQ2hDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUE7WUFFakIsK0NBQStDO1lBQy9DLElBQUksQ0FBQyxHQUFHLFNBQVMsR0FBRyxDQUFDLEdBQUcsRUFBRSxF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