mirror of
https://github.com/TheNetsky/Microsoft-Rewards-Script.git
synced 2026-01-11 19:06:18 +00:00
1.4.0
- Switched from Puppeteer to Playwright - Fixed mobile searches not working - Added fingerprint saving in config - Added mobile search retry in config
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# Microsoft-Rewards-Script
|
# Microsoft-Rewards-Script
|
||||||
Automated Microsoft Rewards script, however this time using TypeScript, Cheerio and Puppeteer.
|
Automated Microsoft Rewards script, however this time using TypeScript, Cheerio and Playwright.
|
||||||
|
|
||||||
Under development, however mainly for personal use!
|
Under development, however mainly for personal use!
|
||||||
|
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "microsoft-rewards-script",
|
"name": "microsoft-rewards-script",
|
||||||
"version": "1.3.2",
|
"version": "1.4.0",
|
||||||
"description": "Automatically do tasks for Microsoft Rewards but in TS!",
|
"description": "Automatically do tasks for Microsoft Rewards but in TS!",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"Bot",
|
"Bot",
|
||||||
"Script",
|
"Script",
|
||||||
"TypeScript",
|
"TypeScript",
|
||||||
"Puppeteer",
|
"Playwright",
|
||||||
"Cheerio"
|
"Cheerio"
|
||||||
],
|
],
|
||||||
"author": "Netsky",
|
"author": "Netsky",
|
||||||
@@ -33,9 +33,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
"cheerio": "^1.0.0-rc.12",
|
"cheerio": "^1.0.0-rc.12",
|
||||||
"fingerprint-generator": "^2.1.45",
|
"fingerprint-generator": "^2.1.46",
|
||||||
"fingerprint-injector": "^2.1.45",
|
"fingerprint-injector": "^2.1.46",
|
||||||
"puppeteer": "^21.6.1",
|
"playwright": "^1.40.1",
|
||||||
"ts-node": "^10.9.2"
|
"ts-node": "^10.9.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import puppeteer from 'puppeteer'
|
import playwright from 'playwright'
|
||||||
import { FingerprintInjector } from 'fingerprint-injector'
|
import { BrowserContext } from 'playwright'
|
||||||
|
|
||||||
|
import { newInjectedContext } from 'fingerprint-injector'
|
||||||
import { FingerprintGenerator } from 'fingerprint-generator'
|
import { FingerprintGenerator } from 'fingerprint-generator'
|
||||||
|
|
||||||
import { MicrosoftRewardsBot } from '../index'
|
import { MicrosoftRewardsBot } from '../index'
|
||||||
import { loadSesion } from '../util/Load'
|
import { loadSessionData, saveFingerprintData } from '../util/Load'
|
||||||
|
|
||||||
import { AccountProxy } from '../interface/Account'
|
import { AccountProxy } from '../interface/Account'
|
||||||
|
|
||||||
@@ -13,63 +15,54 @@ https://botcheck.luminati.io/
|
|||||||
http://f.vision/
|
http://f.vision/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
class Browser {
|
class Browser {
|
||||||
private bot: MicrosoftRewardsBot
|
private bot: MicrosoftRewardsBot
|
||||||
private usedUserAgents: string[] = []
|
|
||||||
|
|
||||||
constructor(bot: MicrosoftRewardsBot) {
|
constructor(bot: MicrosoftRewardsBot) {
|
||||||
this.bot = bot
|
this.bot = bot
|
||||||
}
|
}
|
||||||
|
|
||||||
async createBrowser(email: string, proxy: AccountProxy) {
|
async createBrowser(proxy: AccountProxy, email: string): Promise<BrowserContext> {
|
||||||
// const userAgent = await getUserAgent(isMobile)
|
const browser = await playwright.chromium.launch({
|
||||||
|
//channel: 'msedge', // Uses Edge instead of chrome
|
||||||
const browser = await puppeteer.launch({
|
headless: this.bot.config.headless,
|
||||||
headless: this.bot.config.headless ? 'new' : false,
|
...(proxy.url && { proxy: { username: proxy.username, password: proxy.password, server: `${proxy.url}:${proxy.port}` } }),
|
||||||
userDataDir: await loadSesion(this.bot.config.sessionPath, email),
|
|
||||||
args: [
|
args: [
|
||||||
'--no-sandbox',
|
'--no-sandbox',
|
||||||
'--mute-audio',
|
'--mute-audio',
|
||||||
'--disable-setuid-sandbox',
|
'--disable-setuid-sandbox',
|
||||||
'--ignore-certificate-errors',
|
'--ignore-certificate-errors',
|
||||||
'--ignore-certificate-errors-spki-list',
|
'--ignore-certificate-errors-spki-list',
|
||||||
'--ignore-ssl-errors',
|
'--ignore-ssl-errors'
|
||||||
proxy.url ? `--proxy-server=${proxy.url}:${proxy.port}` : ''
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
let fingerPrintData = new FingerprintGenerator().getFingerprint({
|
const sessionData = await loadSessionData(this.bot.config.sessionPath, email, this.bot.isMobile, this.bot.config.saveFingerprint)
|
||||||
|
|
||||||
|
const fingerpint = sessionData.fingerprint ? sessionData.fingerprint : this.generateFingerprint()
|
||||||
|
|
||||||
|
const context = await newInjectedContext(browser, { fingerprint: fingerpint })
|
||||||
|
|
||||||
|
await context.addCookies(sessionData.cookies)
|
||||||
|
|
||||||
|
if (this.bot.config.saveFingerprint) {
|
||||||
|
await saveFingerprintData(this.bot.config.sessionPath, email, this.bot.isMobile, fingerpint)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bot.log('BROWSER', `Created browser with User-Agent: "${fingerpint.fingerprint.navigator.userAgent}"`)
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
generateFingerprint() {
|
||||||
|
const fingerPrintData = new FingerprintGenerator().getFingerprint({
|
||||||
devices: this.bot.isMobile ? ['mobile'] : ['desktop'],
|
devices: this.bot.isMobile ? ['mobile'] : ['desktop'],
|
||||||
operatingSystems: this.bot.isMobile ? ['android'] : ['windows'],
|
operatingSystems: this.bot.isMobile ? ['android'] : ['windows'],
|
||||||
browsers: ['edge']
|
browsers: ['edge']
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.usedUserAgents) {
|
return fingerPrintData
|
||||||
while (this.usedUserAgents.includes(fingerPrintData.fingerprint.navigator.userAgent)) {
|
|
||||||
fingerPrintData = new FingerprintGenerator().getFingerprint({
|
|
||||||
devices: this.bot.isMobile ? ['mobile'] : ['desktop'],
|
|
||||||
operatingSystems: this.bot.isMobile ? ['android'] : ['windows'],
|
|
||||||
browsers: ['edge']
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.usedUserAgents.push(fingerPrintData.fingerprint.navigator.userAgent)
|
|
||||||
|
|
||||||
// Modify the newPage function to attach the fingerprint
|
|
||||||
const originalNewPage = browser.newPage
|
|
||||||
browser.newPage = async function () {
|
|
||||||
const page = await originalNewPage.apply(browser)
|
|
||||||
await new FingerprintInjector().attachFingerprintToPuppeteer(page, fingerPrintData)
|
|
||||||
return page
|
|
||||||
}
|
|
||||||
|
|
||||||
this.bot.log('BROWSER', `Created browser with User-Agent: "${fingerPrintData.fingerprint.navigator.userAgent}"`)
|
|
||||||
|
|
||||||
return browser
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Browser
|
export default Browser
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
import { CheerioAPI, load } from 'cheerio'
|
import { CheerioAPI, load } from 'cheerio'
|
||||||
|
|
||||||
import { MicrosoftRewardsBot } from '../index'
|
import { MicrosoftRewardsBot } from '../index'
|
||||||
@@ -17,7 +17,7 @@ export default class BrowserFunc {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate the provided page to rewards homepage
|
* Navigate the provided page to rewards homepage
|
||||||
* @param {Page} page Puppeteer page
|
* @param {Page} page Playwright page
|
||||||
*/
|
*/
|
||||||
async goHome(page: Page) {
|
async goHome(page: Page) {
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ export default class BrowserFunc {
|
|||||||
await this.bot.browser.utils.tryDismissCookieBanner(page)
|
await this.bot.browser.utils.tryDismissCookieBanner(page)
|
||||||
|
|
||||||
// Check if account is suspended
|
// Check if account is suspended
|
||||||
const isSuspended = await page.waitForSelector('#suspendedAccountHeader', { visible: true, timeout: 2000 }).then(() => true).catch(() => false)
|
const isSuspended = await page.waitForSelector('#suspendedAccountHeader', { state: 'visible', timeout: 2000 }).then(() => true).catch(() => false)
|
||||||
if (isSuspended) {
|
if (isSuspended) {
|
||||||
this.bot.log('GO-HOME', 'This account is suspended!', 'error')
|
this.bot.log('GO-HOME', 'This account is suspended!', 'error')
|
||||||
throw new Error('Account has been suspended!')
|
throw new Error('Account has been suspended!')
|
||||||
@@ -89,7 +89,7 @@ export default class BrowserFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reload the page to get new data
|
// Reload the page to get new data
|
||||||
await this.bot.homePage.reload({ waitUntil: 'networkidle2' })
|
await this.bot.homePage.reload({ waitUntil: 'domcontentloaded' })
|
||||||
|
|
||||||
const scriptContent = await this.bot.homePage.evaluate(() => {
|
const scriptContent = await this.bot.homePage.evaluate(() => {
|
||||||
const scripts = Array.from(document.querySelectorAll('script'))
|
const scripts = Array.from(document.querySelectorAll('script'))
|
||||||
@@ -180,7 +180,7 @@ export default class BrowserFunc {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse quiz data from provided page
|
* Parse quiz data from provided page
|
||||||
* @param {Page} page Puppeteer page
|
* @param {Page} page Playwright page
|
||||||
* @returns {QuizData} Quiz data object
|
* @returns {QuizData} Quiz data object
|
||||||
*/
|
*/
|
||||||
async getQuizData(page: Page): Promise<QuizData> {
|
async getQuizData(page: Page): Promise<QuizData> {
|
||||||
@@ -214,7 +214,7 @@ export default class BrowserFunc {
|
|||||||
|
|
||||||
async waitForQuizRefresh(page: Page): Promise<boolean> {
|
async waitForQuizRefresh(page: Page): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
await page.waitForSelector('span.rqMCredits', { visible: true, timeout: 10_000 })
|
await page.waitForSelector('span.rqMCredits', { state: 'visible', timeout: 10_000 })
|
||||||
await this.bot.utils.wait(2000)
|
await this.bot.utils.wait(2000)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -226,7 +226,7 @@ export default class BrowserFunc {
|
|||||||
|
|
||||||
async checkQuizCompleted(page: Page): Promise<boolean> {
|
async checkQuizCompleted(page: Page): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
await page.waitForSelector('#quizCompleteContainer', { visible: true, timeout: 2000 })
|
await page.waitForSelector('#quizCompleteContainer', { state: 'visible', timeout: 2000 })
|
||||||
await this.bot.utils.wait(2000)
|
await this.bot.utils.wait(2000)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
|
|
||||||
import { MicrosoftRewardsBot } from '../index'
|
import { MicrosoftRewardsBot } from '../index'
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ export default class BrowserUtil {
|
|||||||
|
|
||||||
for (const button of buttons) {
|
for (const button of buttons) {
|
||||||
try {
|
try {
|
||||||
const element = await page.waitForSelector(button.selector, { visible: true, timeout: 1000 })
|
const element = await page.waitForSelector(button.selector, { state: 'visible', timeout: 1000 })
|
||||||
if (element) {
|
if (element) {
|
||||||
await element.click()
|
await element.click()
|
||||||
result = true
|
result = true
|
||||||
@@ -73,8 +73,8 @@ export default class BrowserUtil {
|
|||||||
try {
|
try {
|
||||||
await this.bot.utils.wait(500)
|
await this.bot.utils.wait(500)
|
||||||
|
|
||||||
const browser = page.browser()
|
const browser = page.context()
|
||||||
const pages = await browser.pages()
|
const pages = browser.pages()
|
||||||
const newTab = pages[pages.length - 1]
|
const newTab = pages[pages.length - 1]
|
||||||
|
|
||||||
if (newTab) {
|
if (newTab) {
|
||||||
@@ -89,8 +89,8 @@ export default class BrowserUtil {
|
|||||||
|
|
||||||
async getTabs(page: Page) {
|
async getTabs(page: Page) {
|
||||||
try {
|
try {
|
||||||
const browser = page.browser()
|
const browser = page.context()
|
||||||
const pages = await browser.pages()
|
const pages = browser.pages()
|
||||||
|
|
||||||
const homeTab = pages[1]
|
const homeTab = pages[1]
|
||||||
let homeTabURL: URL
|
let homeTabURL: URL
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
"baseURL": "https://rewards.bing.com",
|
"baseURL": "https://rewards.bing.com",
|
||||||
"sessionPath": "sessions",
|
"sessionPath": "sessions",
|
||||||
"headless": false,
|
"headless": false,
|
||||||
"runOnZeroPoints": false,
|
"runOnZeroPoints": true,
|
||||||
"clusters": 1,
|
"clusters": 1,
|
||||||
|
"saveFingerprint": false,
|
||||||
"workers": {
|
"workers": {
|
||||||
"doDailySet": true,
|
"doDailySet": true,
|
||||||
"doMorePromotions": true,
|
"doMorePromotions": true,
|
||||||
@@ -18,7 +19,8 @@
|
|||||||
"searchDelay": {
|
"searchDelay": {
|
||||||
"min": 10000,
|
"min": 10000,
|
||||||
"max": 20000
|
"max": 20000
|
||||||
}
|
},
|
||||||
|
"retryMobileSearch": true
|
||||||
},
|
},
|
||||||
"webhook": {
|
"webhook": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
|
|
||||||
import { MicrosoftRewardsBot } from '../index'
|
import { MicrosoftRewardsBot } from '../index'
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
import readline from 'readline'
|
import readline from 'readline'
|
||||||
|
|
||||||
import { MicrosoftRewardsBot } from '../index'
|
import { MicrosoftRewardsBot } from '../index'
|
||||||
@@ -26,13 +26,13 @@ export class Login {
|
|||||||
|
|
||||||
if (!isLoggedIn) {
|
if (!isLoggedIn) {
|
||||||
// Check if account is locked
|
// Check if account is locked
|
||||||
const isLocked = await page.waitForSelector('.serviceAbusePageContainer', { visible: true, timeout: 10_000 }).then(() => true).catch(() => false)
|
const isLocked = await page.waitForSelector('.serviceAbusePageContainer', { state: 'visible', timeout: 10_000 }).then(() => true).catch(() => false)
|
||||||
if (isLocked) {
|
if (isLocked) {
|
||||||
this.bot.log('LOGIN', 'This account has been locked!', 'error')
|
this.bot.log('LOGIN', 'This account has been locked!', 'error')
|
||||||
throw new Error('Account has been locked!')
|
throw new Error('Account has been locked!')
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.waitForSelector('#loginHeader', { visible: true, timeout: 10_000 })
|
await page.waitForSelector('#loginHeader', { state: 'visible', timeout: 10_000 })
|
||||||
|
|
||||||
await this.execLogin(page, email, password)
|
await this.execLogin(page, email, password)
|
||||||
this.bot.log('LOGIN', 'Logged into Microsoft successfully')
|
this.bot.log('LOGIN', 'Logged into Microsoft successfully')
|
||||||
@@ -59,7 +59,7 @@ export class Login {
|
|||||||
this.bot.log('LOGIN', 'Email entered successfully')
|
this.bot.log('LOGIN', 'Email entered successfully')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await page.waitForSelector('#i0118', { visible: true, timeout: 2000 })
|
await page.waitForSelector('#i0118', { state: 'visible', timeout: 2000 })
|
||||||
await this.bot.utils.wait(2000)
|
await this.bot.utils.wait(2000)
|
||||||
|
|
||||||
await page.type('#i0118', password)
|
await page.type('#i0118', password)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
|
|
||||||
import { DashboardData, MorePromotion, PromotionalItem, PunchCard } from '../interface/DashboardData'
|
import { DashboardData, MorePromotion, PromotionalItem, PunchCard } from '../interface/DashboardData'
|
||||||
|
|
||||||
@@ -58,13 +58,13 @@ export class Workers {
|
|||||||
await page.goto(punchCard.parentPromotion.destinationUrl, { referer: this.bot.config.baseURL })
|
await page.goto(punchCard.parentPromotion.destinationUrl, { referer: this.bot.config.baseURL })
|
||||||
|
|
||||||
// Wait for new page to load, max 10 seconds, however try regardless in case of error
|
// Wait for new page to load, max 10 seconds, however try regardless in case of error
|
||||||
await page.waitForNetworkIdle({ timeout: 5_000 }).catch(() => { })
|
await page.waitForLoadState('networkidle', { timeout: 5_000 }).catch(() => { })
|
||||||
|
|
||||||
await this.solveActivities(page, activitiesUncompleted, punchCard)
|
await this.solveActivities(page, activitiesUncompleted, punchCard)
|
||||||
|
|
||||||
page = await this.bot.browser.utils.getLatestTab(page)
|
page = await this.bot.browser.utils.getLatestTab(page)
|
||||||
|
|
||||||
const pages = await (page.browser()).pages()
|
const pages = page.context().pages()
|
||||||
|
|
||||||
if (pages.length > 3) {
|
if (pages.length > 3) {
|
||||||
await page.close()
|
await page.close()
|
||||||
@@ -118,7 +118,7 @@ export class Workers {
|
|||||||
// Reselect the worker page
|
// Reselect the worker page
|
||||||
activityPage = await this.bot.browser.utils.getLatestTab(activityPage)
|
activityPage = await this.bot.browser.utils.getLatestTab(activityPage)
|
||||||
|
|
||||||
const pages = await activityPage.browser().pages()
|
const pages = activityPage.context().pages()
|
||||||
if (pages.length > 3) {
|
if (pages.length > 3) {
|
||||||
await activityPage.close()
|
await activityPage.close()
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ export class Workers {
|
|||||||
Due to common false timeout on this function, we're ignoring the error regardless, if it worked then it's faster,
|
Due to common false timeout on this function, we're ignoring the error regardless, if it worked then it's faster,
|
||||||
if it didn't then it gave enough time for the page to load.
|
if it didn't then it gave enough time for the page to load.
|
||||||
*/
|
*/
|
||||||
await activityPage.waitForNetworkIdle({ timeout: 10_000 }).catch(() => { })
|
await activityPage.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => { })
|
||||||
await this.bot.utils.wait(5000)
|
await this.bot.utils.wait(5000)
|
||||||
|
|
||||||
switch (activity.promotionType) {
|
switch (activity.promotionType) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
|
|
||||||
import { Workers } from '../Workers'
|
import { Workers } from '../Workers'
|
||||||
|
|
||||||
@@ -15,18 +15,18 @@ export class ABC extends Workers {
|
|||||||
const maxIterations = 15
|
const maxIterations = 15
|
||||||
let i
|
let i
|
||||||
for (i = 0; i < maxIterations && !$('span.rw_icon').length; i++) {
|
for (i = 0; i < maxIterations && !$('span.rw_icon').length; i++) {
|
||||||
await page.waitForSelector('.wk_OptionClickClass', { visible: true, timeout: 10_000 })
|
await page.waitForSelector('.wk_OptionClickClass', { state: 'visible', timeout: 10_000 })
|
||||||
|
|
||||||
const answers = $('.wk_OptionClickClass')
|
const answers = $('.wk_OptionClickClass')
|
||||||
const answer = answers[this.bot.utils.randomNumber(0, 2)]?.attribs['id']
|
const answer = answers[this.bot.utils.randomNumber(0, 2)]?.attribs['id']
|
||||||
|
|
||||||
await page.waitForSelector(`#${answer}`, { visible: true, timeout: 10_000 })
|
await page.waitForSelector(`#${answer}`, { state: 'visible', timeout: 10_000 })
|
||||||
|
|
||||||
await this.bot.utils.wait(2000)
|
await this.bot.utils.wait(2000)
|
||||||
await page.click(`#${answer}`) // Click answer
|
await page.click(`#${answer}`) // Click answer
|
||||||
|
|
||||||
await this.bot.utils.wait(4000)
|
await this.bot.utils.wait(4000)
|
||||||
await page.waitForSelector('div.wk_button', { visible: true, timeout: 10_000 })
|
await page.waitForSelector('div.wk_button', { state: 'visible', timeout: 10_000 })
|
||||||
await page.click('div.wk_button') // Click next question button
|
await page.click('div.wk_button') // Click next question button
|
||||||
|
|
||||||
page = await this.bot.browser.utils.getLatestTab(page)
|
page = await this.bot.browser.utils.getLatestTab(page)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
|
|
||||||
import { Workers } from '../Workers'
|
import { Workers } from '../Workers'
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ export class Poll extends Workers {
|
|||||||
try {
|
try {
|
||||||
const buttonId = `#btoption${Math.floor(this.bot.utils.randomNumber(0, 1))}`
|
const buttonId = `#btoption${Math.floor(this.bot.utils.randomNumber(0, 1))}`
|
||||||
|
|
||||||
await page.waitForSelector(buttonId, { visible: true, timeout: 10_000 }).catch(() => { }) // We're gonna click regardless or not
|
await page.waitForSelector(buttonId, { state: 'visible', timeout: 10_000 }).catch(() => { }) // We're gonna click regardless or not
|
||||||
await this.bot.utils.wait(2000)
|
await this.bot.utils.wait(2000)
|
||||||
|
|
||||||
await page.click(buttonId)
|
await page.click(buttonId)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
|
|
||||||
import { Workers } from '../Workers'
|
import { Workers } from '../Workers'
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ export class Quiz extends Workers {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if the quiz has been started or not
|
// Check if the quiz has been started or not
|
||||||
const quizNotStarted = await page.waitForSelector('#rqStartQuiz', { visible: true, timeout: 2000 }).then(() => true).catch(() => false)
|
const quizNotStarted = await page.waitForSelector('#rqStartQuiz', { state: 'visible', timeout: 2000 }).then(() => true).catch(() => false)
|
||||||
if (quizNotStarted) {
|
if (quizNotStarted) {
|
||||||
await page.click('#rqStartQuiz')
|
await page.click('#rqStartQuiz')
|
||||||
} else {
|
} else {
|
||||||
@@ -29,7 +29,7 @@ export class Quiz extends Workers {
|
|||||||
const answers: string[] = []
|
const answers: string[] = []
|
||||||
|
|
||||||
for (let i = 0; i < quizData.numberOfOptions; i++) {
|
for (let i = 0; i < quizData.numberOfOptions; i++) {
|
||||||
const answerSelector = await page.waitForSelector(`#rqAnswerOption${i}`, { visible: true, timeout: 10_000 })
|
const answerSelector = await page.waitForSelector(`#rqAnswerOption${i}`, { state: 'visible', timeout: 10_000 })
|
||||||
const answerAttribute = await answerSelector?.evaluate(el => el.getAttribute('iscorrectoption'))
|
const answerAttribute = await answerSelector?.evaluate(el => el.getAttribute('iscorrectoption'))
|
||||||
|
|
||||||
if (answerAttribute && answerAttribute.toLowerCase() === 'true') {
|
if (answerAttribute && answerAttribute.toLowerCase() === 'true') {
|
||||||
@@ -39,7 +39,7 @@ export class Quiz extends Workers {
|
|||||||
|
|
||||||
// Click the answers
|
// Click the answers
|
||||||
for (const answer of answers) {
|
for (const answer of answers) {
|
||||||
await page.waitForSelector(answer, { visible: true, timeout: 2000 })
|
await page.waitForSelector(answer, { state: 'visible', timeout: 2000 })
|
||||||
|
|
||||||
// Click the answer on page
|
// Click the answer on page
|
||||||
await page.click(answer)
|
await page.click(answer)
|
||||||
@@ -59,7 +59,7 @@ export class Quiz extends Workers {
|
|||||||
|
|
||||||
for (let i = 0; i < quizData.numberOfOptions; i++) {
|
for (let i = 0; i < quizData.numberOfOptions; i++) {
|
||||||
|
|
||||||
const answerSelector = await page.waitForSelector(`#rqAnswerOption${i}`, { visible: true, timeout: 10_000 })
|
const answerSelector = await page.waitForSelector(`#rqAnswerOption${i}`, { state: 'visible', timeout: 10_000 })
|
||||||
const dataOption = await answerSelector?.evaluate(el => el.getAttribute('data-option'))
|
const dataOption = await answerSelector?.evaluate(el => el.getAttribute('data-option'))
|
||||||
|
|
||||||
if (dataOption === correctOption) {
|
if (dataOption === correctOption) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import { Workers } from '../Workers'
|
import { Workers } from '../Workers'
|
||||||
@@ -63,6 +63,12 @@ export class Search extends Workers {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only for mobile searches
|
||||||
|
if (maxLoop > 3 && this.bot.isMobile) {
|
||||||
|
this.bot.log('SEARCH-BING-MOBILE', 'Search didn\'t gain point for 3 iterations, likely bad User-Agent', 'warn')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
// If we didn't gain points for 10 iterations, assume it's stuck
|
// If we didn't gain points for 10 iterations, assume it's stuck
|
||||||
if (maxLoop > 10) {
|
if (maxLoop > 10) {
|
||||||
this.bot.log('SEARCH-BING', 'Search didn\'t gain point for 10 iterations aborting searches', 'warn')
|
this.bot.log('SEARCH-BING', 'Search didn\'t gain point for 10 iterations aborting searches', 'warn')
|
||||||
@@ -71,6 +77,11 @@ export class Search extends Workers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only for mobile searches
|
||||||
|
if (missingPoints > 0 && this.bot.isMobile) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// If we still got remaining search queries, generate extra ones
|
// If we still got remaining search queries, generate extra ones
|
||||||
if (missingPoints > 0) {
|
if (missingPoints > 0) {
|
||||||
this.bot.log('SEARCH-BING', `Search completed but we're missing ${missingPoints} points, generating extra searches`)
|
this.bot.log('SEARCH-BING', `Search completed but we're missing ${missingPoints} points, generating extra searches`)
|
||||||
@@ -121,7 +132,7 @@ export class Search extends Workers {
|
|||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
try {
|
try {
|
||||||
const searchBar = '#sb_form_q'
|
const searchBar = '#sb_form_q'
|
||||||
await searchPage.waitForSelector(searchBar, { visible: true, timeout: 10_000 })
|
await searchPage.waitForSelector(searchBar, { state: 'visible', timeout: 10_000 })
|
||||||
await searchPage.click(searchBar) // Focus on the textarea
|
await searchPage.click(searchBar) // Focus on the textarea
|
||||||
await this.bot.utils.wait(500)
|
await this.bot.utils.wait(500)
|
||||||
await searchPage.keyboard.down('Control')
|
await searchPage.keyboard.down('Control')
|
||||||
@@ -155,20 +166,8 @@ export class Search extends Workers {
|
|||||||
this.bot.log('SEARCH-BING', `Retrying search, attempt ${i}/5`, 'warn')
|
this.bot.log('SEARCH-BING', `Retrying search, attempt ${i}/5`, 'warn')
|
||||||
|
|
||||||
// Reset the tabs
|
// Reset the tabs
|
||||||
const browser = searchPage.browser()
|
|
||||||
const tabs = await browser.pages()
|
|
||||||
const lastTab = await this.bot.browser.utils.getLatestTab(searchPage)
|
const lastTab = await this.bot.browser.utils.getLatestTab(searchPage)
|
||||||
|
await this.closeTabs(lastTab, this.searchPageURL)
|
||||||
if (tabs.length === 4) {
|
|
||||||
await lastTab.close()
|
|
||||||
|
|
||||||
} else if (tabs.length === 2) {
|
|
||||||
const newPage = await browser.newPage()
|
|
||||||
await newPage.goto(this.searchPageURL)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
await lastTab.goBack()
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.bot.utils.wait(4000)
|
await this.bot.utils.wait(4000)
|
||||||
}
|
}
|
||||||
@@ -276,19 +275,8 @@ export class Search extends Workers {
|
|||||||
// Check if the URL is different from the original one, don't loop more than 5 times.
|
// Check if the URL is different from the original one, don't loop more than 5 times.
|
||||||
let i = 0
|
let i = 0
|
||||||
while (lastTabURL.href !== searchListingURL.href && i < 5) {
|
while (lastTabURL.href !== searchListingURL.href && i < 5) {
|
||||||
const browser = page.browser()
|
|
||||||
const tabs = await browser.pages()
|
|
||||||
|
|
||||||
if (tabs.length === 4) {
|
await this.closeTabs(lastTab, searchListingURL.href)
|
||||||
await lastTab.close()
|
|
||||||
|
|
||||||
} else if (tabs.length === 2) {
|
|
||||||
const newPage = await browser.newPage()
|
|
||||||
await newPage.goto(searchListingURL.href)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
await lastTab.goBack()
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of loop, refresh lastPage
|
// End of loop, refresh lastPage
|
||||||
lastTab = await this.bot.browser.utils.getLatestTab(page) // Finally update the lastTab var again
|
lastTab = await this.bot.browser.utils.getLatestTab(page) // Finally update the lastTab var again
|
||||||
@@ -301,6 +289,26 @@ export class Search extends Workers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async closeTabs(lastTab: Page, url: string) {
|
||||||
|
const browser = lastTab.context()
|
||||||
|
const tabs = browser.pages()
|
||||||
|
|
||||||
|
// If more than 3 tabs are open, close the last tab
|
||||||
|
if (tabs.length > 2) {
|
||||||
|
await lastTab.close()
|
||||||
|
|
||||||
|
// If only 1 tab is open, open a new one to search in
|
||||||
|
} else if (tabs.length === 1) {
|
||||||
|
const newPage = await browser.newPage()
|
||||||
|
await newPage.goto(url)
|
||||||
|
|
||||||
|
// Else go back one page
|
||||||
|
} else {
|
||||||
|
await lastTab.goBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private calculatePoints(counters: Counters) {
|
private calculatePoints(counters: Counters) {
|
||||||
const mobileData = counters.mobileSearch?.[0] // Mobile searches
|
const mobileData = counters.mobileSearch?.[0] // Mobile searches
|
||||||
const genericData = counters.pcSearch?.[0] // Normal searches
|
const genericData = counters.pcSearch?.[0] // Normal searches
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
|
|
||||||
import { Workers } from '../Workers'
|
import { Workers } from '../Workers'
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ export class ThisOrThat extends Workers {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if the quiz has been started or not
|
// Check if the quiz has been started or not
|
||||||
const quizNotStarted = await page.waitForSelector('#rqStartQuiz', { visible: true, timeout: 2000 }).then(() => true).catch(() => false)
|
const quizNotStarted = await page.waitForSelector('#rqStartQuiz', { state: 'visible', timeout: 2000 }).then(() => true).catch(() => false)
|
||||||
if (quizNotStarted) {
|
if (quizNotStarted) {
|
||||||
await page.click('#rqStartQuiz')
|
await page.click('#rqStartQuiz')
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Page } from 'puppeteer'
|
import { Page } from 'playwright'
|
||||||
|
|
||||||
import { Workers } from '../Workers'
|
import { Workers } from '../Workers'
|
||||||
|
|
||||||
|
|||||||
55
src/index.ts
55
src/index.ts
@@ -1,5 +1,5 @@
|
|||||||
import cluster from 'cluster'
|
import cluster from 'cluster'
|
||||||
import { Page } from 'puppeteer'
|
import { BrowserContext, Page } from 'playwright'
|
||||||
|
|
||||||
import Browser from './browser/Browser'
|
import Browser from './browser/Browser'
|
||||||
import BrowserFunc from './browser/BrowserFunc'
|
import BrowserFunc from './browser/BrowserFunc'
|
||||||
@@ -7,7 +7,7 @@ import BrowserUtil from './browser/BrowserUtil'
|
|||||||
|
|
||||||
import { log } from './util/Logger'
|
import { log } from './util/Logger'
|
||||||
import Util from './util/Utils'
|
import Util from './util/Utils'
|
||||||
import { loadAccounts, loadConfig } from './util/Load'
|
import { loadAccounts, loadConfig, saveSessionData } from './util/Load'
|
||||||
|
|
||||||
import { Login } from './functions/Login'
|
import { Login } from './functions/Login'
|
||||||
import { Workers } from './functions/Workers'
|
import { Workers } from './functions/Workers'
|
||||||
@@ -125,18 +125,8 @@ export class MicrosoftRewardsBot {
|
|||||||
|
|
||||||
// Desktop
|
// Desktop
|
||||||
async Desktop(account: Account) {
|
async Desktop(account: Account) {
|
||||||
const browser = await this.browserFactory.createBrowser(account.email, account.proxy)
|
const browser = await this.browserFactory.createBrowser(account.proxy, account.email)
|
||||||
this.homePage = await browser.newPage()
|
this.homePage = await browser.newPage()
|
||||||
let pages = await browser.pages()
|
|
||||||
|
|
||||||
// If for some reason the browser initializes with more than 2 pages, close these
|
|
||||||
while (pages.length > 2) {
|
|
||||||
await pages[0]?.close()
|
|
||||||
pages = await browser.pages()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log into proxy
|
|
||||||
await this.homePage.authenticate({ username: account.proxy.username, password: account.proxy.password })
|
|
||||||
|
|
||||||
log('MAIN', 'Starting DESKTOP browser')
|
log('MAIN', 'Starting DESKTOP browser')
|
||||||
|
|
||||||
@@ -156,7 +146,7 @@ export class MicrosoftRewardsBot {
|
|||||||
log('MAIN', 'No points to earn and "runOnZeroPoints" is set to "false", stopping!')
|
log('MAIN', 'No points to earn and "runOnZeroPoints" is set to "false", stopping!')
|
||||||
|
|
||||||
// Close desktop browser
|
// Close desktop browser
|
||||||
return await browser.close()
|
return await this.closeBrowser(browser, account.email)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open a new tab to where the tasks are going to be completed
|
// Open a new tab to where the tasks are going to be completed
|
||||||
@@ -185,25 +175,20 @@ export class MicrosoftRewardsBot {
|
|||||||
await this.activities.doSearch(workerPage, data)
|
await this.activities.doSearch(workerPage, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save cookies
|
||||||
|
const cookies = await browser.cookies()
|
||||||
|
await saveSessionData(this.config.sessionPath, account.email, this.isMobile, cookies)
|
||||||
|
|
||||||
// Close desktop browser
|
// Close desktop browser
|
||||||
await browser.close()
|
return await this.closeBrowser(browser, account.email)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mobile
|
// Mobile
|
||||||
async Mobile(account: Account) {
|
async Mobile(account: Account) {
|
||||||
this.isMobile = true
|
this.isMobile = true
|
||||||
|
|
||||||
const browser = await this.browserFactory.createBrowser(account.email, account.proxy)
|
const browser = await this.browserFactory.createBrowser(account.proxy, account.email)
|
||||||
this.homePage = await browser.newPage()
|
this.homePage = await browser.newPage()
|
||||||
let pages = await browser.pages()
|
|
||||||
|
|
||||||
// If for some reason the browser initializes with more than 2 pages, close these
|
|
||||||
while (pages.length > 2) {
|
|
||||||
await pages[0]?.close()
|
|
||||||
pages = await browser.pages()
|
|
||||||
}
|
|
||||||
// Log into proxy
|
|
||||||
await this.homePage.authenticate({ username: account.proxy.username, password: account.proxy.password })
|
|
||||||
|
|
||||||
log('MAIN', 'Starting MOBILE browser')
|
log('MAIN', 'Starting MOBILE browser')
|
||||||
|
|
||||||
@@ -218,7 +203,7 @@ export class MicrosoftRewardsBot {
|
|||||||
log('MAIN', 'No mobile searches found, stopping!')
|
log('MAIN', 'No mobile searches found, stopping!')
|
||||||
|
|
||||||
// Close mobile browser
|
// Close mobile browser
|
||||||
return await browser.close()
|
return await this.closeBrowser(browser, account.email)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open a new tab to where the tasks are going to be completed
|
// Open a new tab to where the tasks are going to be completed
|
||||||
@@ -235,11 +220,12 @@ export class MicrosoftRewardsBot {
|
|||||||
const mobileSearchPoints = (await this.browser.func.getSearchPoints()).mobileSearch?.[0]
|
const mobileSearchPoints = (await this.browser.func.getSearchPoints()).mobileSearch?.[0]
|
||||||
|
|
||||||
// If the remaining mobile points does not equal 0, restart and assume the generated UA is invalid
|
// If the remaining mobile points does not equal 0, restart and assume the generated UA is invalid
|
||||||
if (mobileSearchPoints && ((mobileSearchPoints.pointProgressMax - mobileSearchPoints.pointProgress) > 0)) {
|
// Retry until all points are gathered when (retryMobileSearch is enabled)
|
||||||
log('MAIN', 'Unable to complete mobile searches, bad User-Agent?, retrying...')
|
if (this.config.searchSettings.retryMobileSearch && mobileSearchPoints && ((mobileSearchPoints.pointProgressMax - mobileSearchPoints.pointProgress) > 0)) {
|
||||||
|
log('MAIN', 'Unable to complete mobile searches, bad User-Agent? Retrying...')
|
||||||
|
|
||||||
// Close mobile browser
|
// Close mobile browser
|
||||||
await browser.close()
|
await this.closeBrowser(browser, account.email)
|
||||||
|
|
||||||
// Retry
|
// Retry
|
||||||
await this.Mobile(account)
|
await this.Mobile(account)
|
||||||
@@ -254,10 +240,21 @@ export class MicrosoftRewardsBot {
|
|||||||
log('MAIN-POINTS', `The script collected ${this.collectedPoints} points today`)
|
log('MAIN-POINTS', `The script collected ${this.collectedPoints} points today`)
|
||||||
|
|
||||||
// Close mobile browser
|
// Close mobile browser
|
||||||
|
return await this.closeBrowser(browser, account.email)
|
||||||
|
}
|
||||||
|
|
||||||
|
private async closeBrowser(browser: BrowserContext, email: string) {
|
||||||
|
// Save cookies
|
||||||
|
const cookies = await browser.cookies()
|
||||||
|
await saveSessionData(this.config.sessionPath, email, this.isMobile, cookies)
|
||||||
|
|
||||||
|
// Close browser
|
||||||
await browser.close()
|
await browser.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const bot = new MicrosoftRewardsBot()
|
const bot = new MicrosoftRewardsBot()
|
||||||
|
|
||||||
// Initialize accounts first and then start the bot
|
// Initialize accounts first and then start the bot
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface Config {
|
|||||||
workers: Workers;
|
workers: Workers;
|
||||||
searchSettings: SearchSettings;
|
searchSettings: SearchSettings;
|
||||||
webhook: Webhook;
|
webhook: Webhook;
|
||||||
|
saveFingerprint: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchSettings {
|
export interface SearchSettings {
|
||||||
@@ -14,6 +15,7 @@ export interface SearchSettings {
|
|||||||
scrollRandomResults: boolean;
|
scrollRandomResults: boolean;
|
||||||
clickRandomResults: boolean;
|
clickRandomResults: boolean;
|
||||||
searchDelay: SearchDelay;
|
searchDelay: SearchDelay;
|
||||||
|
retryMobileSearch: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchDelay {
|
export interface SearchDelay {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
import { Cookie } from 'playwright'
|
||||||
|
import { BrowserFingerprintWithHeaders } from 'fingerprint-generator'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
|
|
||||||
import { Account } from '../interface/Account'
|
import { Account } from '../interface/Account'
|
||||||
import { Config } from '../interface/Config'
|
import { Config } from '../interface/Config'
|
||||||
|
|
||||||
@@ -34,7 +37,37 @@ export function loadConfig(): Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadSesion(sessionPath: string, email: string): Promise<string> {
|
export async function loadSessionData(sessionPath: string, email: string, isMobile: boolean, getFingerprint: boolean) {
|
||||||
|
try {
|
||||||
|
// Fetch cookie file
|
||||||
|
const cookieFile = path.join(__dirname, '../browser/', sessionPath, email, `${isMobile ? 'mobile_cookies' : 'desktop_cookies'}.json`)
|
||||||
|
|
||||||
|
let cookies: Cookie[] = []
|
||||||
|
if (fs.existsSync(cookieFile)) {
|
||||||
|
const cookiesData = await fs.promises.readFile(cookieFile, 'utf-8')
|
||||||
|
cookies = JSON.parse(cookiesData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch fingerprint file
|
||||||
|
const fingerprintFile = path.join(__dirname, '../browser/', sessionPath, email, `${isMobile ? 'mobile_fingerpint' : 'desktop_fingerpint'}.json`)
|
||||||
|
|
||||||
|
let fingerprint!: BrowserFingerprintWithHeaders
|
||||||
|
if (getFingerprint && fs.existsSync(fingerprintFile)) {
|
||||||
|
const fingerprintData = await fs.promises.readFile(fingerprintFile, 'utf-8')
|
||||||
|
fingerprint = JSON.parse(fingerprintData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
cookies: cookies,
|
||||||
|
fingerprint: fingerprint
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error as string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveSessionData(sessionPath: string, email: string, isMobile: boolean, cookies: Cookie[]): Promise<string> {
|
||||||
try {
|
try {
|
||||||
// Fetch path
|
// Fetch path
|
||||||
const sessionDir = path.join(__dirname, '../browser/', sessionPath, email)
|
const sessionDir = path.join(__dirname, '../browser/', sessionPath, email)
|
||||||
@@ -44,6 +77,28 @@ export async function loadSesion(sessionPath: string, email: string): Promise<st
|
|||||||
await fs.promises.mkdir(sessionDir, { recursive: true })
|
await fs.promises.mkdir(sessionDir, { recursive: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save cookies to a file
|
||||||
|
await fs.promises.writeFile(path.join(sessionDir, `${isMobile ? 'mobile_cookies' : 'desktop_cookies'}.json`), JSON.stringify(cookies))
|
||||||
|
|
||||||
|
return sessionDir
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error as string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveFingerprintData(sessionPath: string, email: string, isMobile: boolean, fingerpint: BrowserFingerprintWithHeaders): Promise<string> {
|
||||||
|
try {
|
||||||
|
// Fetch path
|
||||||
|
const sessionDir = path.join(__dirname, '../browser/', sessionPath, email)
|
||||||
|
|
||||||
|
// Create session dir
|
||||||
|
if (!fs.existsSync(sessionDir)) {
|
||||||
|
await fs.promises.mkdir(sessionDir, { recursive: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save fingerprint to a file
|
||||||
|
await fs.promises.writeFile(path.join(sessionDir, `${isMobile ? 'mobile_fingerpint' : 'desktop_fingerpint'}.json`), JSON.stringify(fingerpint))
|
||||||
|
|
||||||
return sessionDir
|
return sessionDir
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error as string)
|
throw new Error(error as string)
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export async function getEdgeVersions() {
|
|||||||
|
|
||||||
export function getSystemComponents(mobile: boolean): string {
|
export function getSystemComponents(mobile: boolean): string {
|
||||||
const osId: string = mobile ? 'Linux' : 'Windows NT 10.0'
|
const osId: string = mobile ? 'Linux' : 'Windows NT 10.0'
|
||||||
const uaPlatform: string = mobile ? 'Android 13' : 'Win64; x64'
|
const uaPlatform: string = mobile ? `Android 1${Math.floor(Math.random() * 5)}` : 'Win64; x64'
|
||||||
|
|
||||||
if (mobile) {
|
if (mobile) {
|
||||||
return `${uaPlatform}; ${osId}; K`
|
return `${uaPlatform}; ${osId}; K`
|
||||||
|
|||||||
Reference in New Issue
Block a user