mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-11 09:46:16 +00:00
Refactor: Improve CAPTCHA handling and reduce delays in the account creation process
This commit is contained in:
@@ -1546,19 +1546,19 @@ export class AccountCreator {
|
|||||||
|
|
||||||
private async waitForCaptcha(): Promise<boolean> {
|
private async waitForCaptcha(): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
// Wait a bit to let the page load
|
log(false, 'CREATOR', '🔍 Checking for CAPTCHA...', 'log', 'cyan')
|
||||||
await this.humanDelay(1500, 2500)
|
await this.humanDelay(1500, 2500)
|
||||||
|
|
||||||
// Check for CAPTCHA iframe (most reliable indicator)
|
// Check for CAPTCHA iframe (most reliable)
|
||||||
const captchaIframe = this.page.locator('iframe[data-testid="humanCaptchaIframe"]').first()
|
const captchaIframe = this.page.locator('iframe[data-testid="humanCaptchaIframe"]').first()
|
||||||
const iframeVisible = await captchaIframe.isVisible().catch(() => false)
|
const iframeVisible = await captchaIframe.isVisible().catch(() => false)
|
||||||
|
|
||||||
if (iframeVisible) {
|
if (iframeVisible) {
|
||||||
log(false, 'CREATOR', 'CAPTCHA detected via iframe', 'warn', 'yellow')
|
log(false, 'CREATOR', '🤖 CAPTCHA DETECTED via iframe - WAITING FOR HUMAN', 'warn', 'yellow')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check multiple indicators for CAPTCHA
|
// Check multiple CAPTCHA indicators
|
||||||
const captchaIndicators = [
|
const captchaIndicators = [
|
||||||
'h1[data-testid="title"]',
|
'h1[data-testid="title"]',
|
||||||
'div[id*="captcha"]',
|
'div[id*="captcha"]',
|
||||||
@@ -1573,8 +1573,8 @@ export class AccountCreator {
|
|||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
const text = await element.textContent().catch(() => '')
|
const text = await element.textContent().catch(() => '')
|
||||||
|
log(false, 'CREATOR', `Found element: ${selector} = "${text?.substring(0, 50)}"`, 'log', 'gray')
|
||||||
|
|
||||||
// Check for CAPTCHA-related keywords
|
|
||||||
if (text && (
|
if (text && (
|
||||||
text.toLowerCase().includes('vérif') ||
|
text.toLowerCase().includes('vérif') ||
|
||||||
text.toLowerCase().includes('verify') ||
|
text.toLowerCase().includes('verify') ||
|
||||||
@@ -1584,63 +1584,54 @@ export class AccountCreator {
|
|||||||
text.toLowerCase().includes('captcha') ||
|
text.toLowerCase().includes('captcha') ||
|
||||||
text.toLowerCase().includes('prove you')
|
text.toLowerCase().includes('prove you')
|
||||||
)) {
|
)) {
|
||||||
log(false, 'CREATOR', `CAPTCHA detected with text: ${text.substring(0, 50)}`, 'warn', 'yellow')
|
log(false, 'CREATOR', `🤖 CAPTCHA DETECTED: "${text.substring(0, 50)}" - WAITING FOR HUMAN`, 'warn', 'yellow')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log(false, 'CREATOR', '✅ No CAPTCHA detected', 'log', 'green')
|
||||||
return false
|
return false
|
||||||
} catch {
|
} catch (error) {
|
||||||
|
log(false, 'CREATOR', `Error checking CAPTCHA: ${error}`, 'warn', 'yellow')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async waitForCaptchaSolved(): Promise<void> {
|
private async waitForCaptchaSolved(): Promise<void> {
|
||||||
const maxWaitTime = 10 * 60 * 1000 // 10 minutes
|
const maxWaitTime = 10 * 60 * 1000
|
||||||
const startTime = Date.now()
|
const startTime = Date.now()
|
||||||
let lastLogTime = startTime
|
let lastLogTime = startTime
|
||||||
|
|
||||||
while (Date.now() - startTime < maxWaitTime) {
|
while (Date.now() - startTime < maxWaitTime) {
|
||||||
try {
|
try {
|
||||||
// Log progress every 30 seconds
|
|
||||||
if (Date.now() - lastLogTime > 30000) {
|
if (Date.now() - lastLogTime > 30000) {
|
||||||
const elapsed = Math.floor((Date.now() - startTime) / 1000)
|
const elapsed = Math.floor((Date.now() - startTime) / 1000)
|
||||||
log(false, 'CREATOR', `Still waiting for CAPTCHA... (${elapsed}s elapsed)`, 'log', 'yellow')
|
log(false, 'CREATOR', `⏳ Still waiting for CAPTCHA solution... (${elapsed}s)`, 'log', 'yellow')
|
||||||
lastLogTime = Date.now()
|
lastLogTime = Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if CAPTCHA is still present
|
|
||||||
const captchaStillPresent = await this.waitForCaptcha()
|
const captchaStillPresent = await this.waitForCaptcha()
|
||||||
|
|
||||||
if (!captchaStillPresent) {
|
if (!captchaStillPresent) {
|
||||||
// CAPTCHA solved! But account creation may still be in progress
|
log(false, 'CREATOR', '✅ CAPTCHA SOLVED! Processing account creation...', 'log', 'green')
|
||||||
log(false, 'CREATOR', '✅ CAPTCHA solved! Waiting for account creation...', 'log', 'green')
|
|
||||||
|
|
||||||
// CRITICAL: Wait MUCH longer for Microsoft to process
|
await this.humanDelay(3000, 5000)
|
||||||
log(false, 'CREATOR', 'Giving Microsoft extra time to process (15-20s)...', 'log', 'cyan')
|
|
||||||
await this.humanDelay(15000, 20000) // INCREASED from 3-5s
|
|
||||||
|
|
||||||
// CRITICAL: Wait for Microsoft to finish creating the account
|
|
||||||
await this.waitForAccountCreation()
|
await this.waitForAccountCreation()
|
||||||
|
await this.humanDelay(2000, 3000)
|
||||||
// CRITICAL: Extra delay after account creation
|
|
||||||
log(false, 'CREATOR', 'Account creation complete, stabilizing (10-15s)...', 'log', 'cyan')
|
|
||||||
await this.humanDelay(10000, 15000)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait before checking again
|
|
||||||
await this.page.waitForTimeout(2000)
|
await this.page.waitForTimeout(2000)
|
||||||
|
|
||||||
} catch {
|
} catch (error) {
|
||||||
// Error checking, assume CAPTCHA is solved
|
log(false, 'CREATOR', `Error in CAPTCHA wait: ${error}`, 'warn', 'yellow')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('CAPTCHA solving timeout - waited 10 minutes')
|
throw new Error('CAPTCHA timeout - 10 minutes exceeded')
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handlePostCreationQuestions(): Promise<void> {
|
private async handlePostCreationQuestions(): Promise<void> {
|
||||||
@@ -1804,99 +1795,22 @@ export class AccountCreator {
|
|||||||
try {
|
try {
|
||||||
log(false, 'CREATOR', 'Navigating to rewards.bing.com...', 'log', 'cyan')
|
log(false, 'CREATOR', 'Navigating to rewards.bing.com...', 'log', 'cyan')
|
||||||
|
|
||||||
await this.page.goto('https://rewards.bing.com/', {
|
|
||||||
waitUntil: 'networkidle',
|
|
||||||
timeout: 60000
|
|
||||||
})
|
|
||||||
|
|
||||||
// Wait for page to stabilize after navigation (REDUCED)
|
|
||||||
await this.waitForPageStable('REWARDS_PAGE', 15000)
|
|
||||||
await this.humanDelay(3000, 5000)
|
|
||||||
|
|
||||||
const currentUrl = this.page.url()
|
|
||||||
log(false, 'CREATOR', `Current URL: ${currentUrl}`, 'log', 'cyan')
|
|
||||||
|
|
||||||
// CRITICAL: Verify we're actually on rewards page and logged in
|
|
||||||
if (!currentUrl.includes('rewards.bing.com')) {
|
|
||||||
if (currentUrl.includes('login.live.com')) {
|
|
||||||
log(false, 'CREATOR', '⚠️ Still on login page - account may not be fully activated', 'warn', 'yellow')
|
|
||||||
|
|
||||||
// Wait before retry (REDUCED)
|
|
||||||
await this.humanDelay(5000, 8000)
|
|
||||||
|
|
||||||
await this.page.goto('https://rewards.bing.com/', {
|
await this.page.goto('https://rewards.bing.com/', {
|
||||||
waitUntil: 'networkidle',
|
waitUntil: 'networkidle',
|
||||||
timeout: 30000
|
timeout: 30000
|
||||||
})
|
})
|
||||||
await this.waitForPageStable('REWARDS_RETRY', 15000)
|
|
||||||
await this.humanDelay(3000, 5000)
|
|
||||||
} else {
|
|
||||||
log(false, 'CREATOR', `⚠️ Unexpected URL: ${currentUrl}`, 'warn', 'yellow')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log(false, 'CREATOR', '✅ Successfully navigated to rewards.bing.com', 'log', 'green')
|
await this.waitForPageStable('REWARDS_PAGE', 7000)
|
||||||
|
|
||||||
// CRITICAL: Wait LONGER for user identity to load before declaring success
|
|
||||||
log(false, 'CREATOR', 'Final wait for complete page load (8-12s)...', 'log', 'cyan')
|
|
||||||
await this.humanDelay(8000, 12000) // INCREASED from 5-7s
|
|
||||||
|
|
||||||
// CRITICAL: Verify user identity is loaded
|
|
||||||
log(false, 'CREATOR', 'Verifying user identity...', 'log', 'cyan')
|
|
||||||
|
|
||||||
const identitySelectors = [
|
|
||||||
'[data-bi-id="userIdentity"]',
|
|
||||||
'[id*="user"]',
|
|
||||||
'button[aria-label*="Account"]',
|
|
||||||
'#id_n', // User dropdown
|
|
||||||
'.mee_header_profile' // Profile area
|
|
||||||
]
|
|
||||||
|
|
||||||
let identityVerified = false
|
|
||||||
for (const selector of identitySelectors) {
|
|
||||||
const element = this.page.locator(selector).first()
|
|
||||||
const visible = await element.isVisible().catch(() => false)
|
|
||||||
|
|
||||||
if (visible) {
|
|
||||||
const text = await element.textContent().catch(() => '')
|
|
||||||
if (text && text.trim().length > 0) {
|
|
||||||
log(false, 'CREATOR', `✅ Verified identity: ${text.substring(0, 50)}`, 'log', 'green')
|
|
||||||
identityVerified = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!identityVerified) {
|
|
||||||
log(false, 'CREATOR', '⚠️ Could not verify user identity on page', 'warn', 'yellow')
|
|
||||||
|
|
||||||
// Wait and check again (REDUCED)
|
|
||||||
await this.humanDelay(3000, 5000)
|
|
||||||
|
|
||||||
for (const selector of identitySelectors) {
|
|
||||||
const element = this.page.locator(selector).first()
|
|
||||||
const visible = await element.isVisible().catch(() => false)
|
|
||||||
|
|
||||||
if (visible) {
|
|
||||||
log(false, 'CREATOR', '✅ Identity verified on retry', 'log', 'green')
|
|
||||||
identityVerified = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (identityVerified) {
|
|
||||||
log(false, 'CREATOR', '✅ Account is active and logged in!', 'log', 'green')
|
|
||||||
} else {
|
|
||||||
log(false, 'CREATOR', '⚠️ Account state uncertain - proceeding anyway', 'warn', 'yellow')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle popups and tour (REDUCED delays)
|
|
||||||
await this.humanDelay(2000, 3000)
|
await this.humanDelay(2000, 3000)
|
||||||
await this.handleRewardsWelcomeTour()
|
|
||||||
|
|
||||||
|
log(false, 'CREATOR', '✅ On rewards.bing.com', 'log', 'green')
|
||||||
|
|
||||||
|
// Clear cookies on rewards page
|
||||||
|
await this.dismissCookieBanner()
|
||||||
|
|
||||||
|
// Handle "Get started" popup (ReferAndEarn)
|
||||||
await this.humanDelay(2000, 3000)
|
await this.humanDelay(2000, 3000)
|
||||||
await this.handleRewardsPopups()
|
await this.handleGetStartedPopup()
|
||||||
|
|
||||||
// Referral enrollment if needed
|
// Referral enrollment if needed
|
||||||
if (this.referralUrl) {
|
if (this.referralUrl) {
|
||||||
@@ -1910,12 +1824,76 @@ export class AccountCreator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleRewardsWelcomeTour(): Promise<void> {
|
private async dismissCookieBanner(): Promise<void> {
|
||||||
// Page loads fast, reduced delays
|
try {
|
||||||
await this.waitForPageStable('WELCOME_TOUR', 10000)
|
log(false, 'CREATOR', '🍪 Checking for cookie banner...', 'log', 'cyan')
|
||||||
|
|
||||||
|
const rejectButtonSelectors = [
|
||||||
|
'button#bnp_btn_reject',
|
||||||
|
'button[id*="reject"]',
|
||||||
|
'button:has-text("Reject")',
|
||||||
|
'button:has-text("Refuser")',
|
||||||
|
'a:has-text("Reject")',
|
||||||
|
'a:has-text("Refuser")'
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const selector of rejectButtonSelectors) {
|
||||||
|
const button = this.page.locator(selector).first()
|
||||||
|
const visible = await button.isVisible({ timeout: 2000 }).catch(() => false)
|
||||||
|
|
||||||
|
if (visible) {
|
||||||
|
log(false, 'CREATOR', '✅ Rejecting cookies', 'log', 'green')
|
||||||
|
await button.click()
|
||||||
|
await this.humanDelay(1000, 1500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log(false, 'CREATOR', 'No cookie banner found', 'log', 'gray')
|
||||||
|
} catch (error) {
|
||||||
|
log(false, 'CREATOR', `Cookie banner error: ${error}`, 'log', 'gray')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleGetStartedPopup(): Promise<void> {
|
||||||
|
try {
|
||||||
|
log(false, 'CREATOR', '🎯 Checking for "Get started" popup...', 'log', 'cyan')
|
||||||
|
await this.humanDelay(2000, 3000)
|
||||||
|
|
||||||
|
// Check for ReferAndEarn popup
|
||||||
|
const popupIndicator = this.page.locator('img[src*="ReferAndEarnPopUpImgUpdated"]').first()
|
||||||
|
const popupVisible = await popupIndicator.isVisible({ timeout: 3000 }).catch(() => false)
|
||||||
|
|
||||||
|
if (!popupVisible) {
|
||||||
|
log(false, 'CREATOR', 'No "Get started" popup found', 'log', 'gray')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log(false, 'CREATOR', '✅ Found "Get started" popup', 'log', 'green')
|
||||||
|
await this.humanDelay(1000, 2000)
|
||||||
|
|
||||||
|
// Click "Get started" button
|
||||||
|
const getStartedButton = this.page.locator('a#reward_pivot_earn, a.dashboardPopUpPopUpSelectButton').first()
|
||||||
|
const buttonVisible = await getStartedButton.isVisible({ timeout: 2000 }).catch(() => false)
|
||||||
|
|
||||||
|
if (buttonVisible) {
|
||||||
|
log(false, 'CREATOR', '🎯 Clicking "Get started"', 'log', 'cyan')
|
||||||
|
await getStartedButton.click()
|
||||||
|
await this.humanDelay(2000, 3000)
|
||||||
|
await this.waitForPageStable('AFTER_GET_STARTED', 5000)
|
||||||
|
log(false, 'CREATOR', '✅ Clicked "Get started"', 'log', 'green')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
log(false, 'CREATOR', `Get started popup error: ${error}`, 'log', 'gray')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unused - kept for future use if needed
|
||||||
|
/*
|
||||||
|
private async handleRewardsWelcomeTour(): Promise<void> {
|
||||||
|
await this.waitForPageStable('WELCOME_TOUR', 7000)
|
||||||
await this.humanDelay(2000, 3000)
|
await this.humanDelay(2000, 3000)
|
||||||
|
|
||||||
// Try to handle the welcome tour (multiple Next buttons)
|
|
||||||
const maxClicks = 5
|
const maxClicks = 5
|
||||||
for (let i = 0; i < maxClicks; i++) {
|
for (let i = 0; i < maxClicks; i++) {
|
||||||
// Check for welcome tour indicators
|
// Check for welcome tour indicators
|
||||||
@@ -1997,7 +1975,9 @@ export class AccountCreator {
|
|||||||
await this.humanDelay(1000, 1500)
|
await this.humanDelay(1000, 1500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
private async handleRewardsPopups(): Promise<void> {
|
private async handleRewardsPopups(): Promise<void> {
|
||||||
await this.waitForPageStable('REWARDS_POPUPS', 10000)
|
await this.waitForPageStable('REWARDS_POPUPS', 10000)
|
||||||
await this.humanDelay(2000, 3000)
|
await this.humanDelay(2000, 3000)
|
||||||
@@ -2068,58 +2048,37 @@ export class AccountCreator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
private async ensureRewardsEnrollment(): Promise<void> {
|
private async ensureRewardsEnrollment(): Promise<void> {
|
||||||
if (!this.referralUrl) return
|
if (!this.referralUrl) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
log(false, 'CREATOR', '🔗 Reloading referral URL for enrollment...', 'log', 'cyan')
|
||||||
|
|
||||||
await this.page.goto(this.referralUrl, {
|
await this.page.goto(this.referralUrl, {
|
||||||
waitUntil: 'networkidle',
|
waitUntil: 'networkidle',
|
||||||
timeout: 30000
|
timeout: 30000
|
||||||
})
|
})
|
||||||
|
|
||||||
await this.waitForPageStable('REFERRAL_ENROLLMENT', 10000)
|
await this.waitForPageStable('REFERRAL_ENROLLMENT', 7000)
|
||||||
await this.humanDelay(2000, 3000)
|
await this.humanDelay(2000, 3000)
|
||||||
|
|
||||||
// Look for "Join Microsoft Rewards" button
|
// Click "Join Microsoft Rewards" button
|
||||||
const joinButtonSelectors = [
|
const joinButton = this.page.locator('a#start-earning-rewards-link').first()
|
||||||
'a#start-earning-rewards-link',
|
const joinVisible = await joinButton.isVisible({ timeout: 3000 }).catch(() => false)
|
||||||
'a.cta.learn-more-btn',
|
|
||||||
'a[href*="createNewUser"]',
|
|
||||||
'a:has-text("Join Microsoft Rewards")',
|
|
||||||
'a:has-text("Rejoindre Microsoft Rewards")',
|
|
||||||
'button:has-text("Join")',
|
|
||||||
'button:has-text("Rejoindre")'
|
|
||||||
]
|
|
||||||
|
|
||||||
let joined = false
|
if (joinVisible) {
|
||||||
for (const selector of joinButtonSelectors) {
|
log(false, 'CREATOR', '🎯 Clicking "Join Microsoft Rewards"', 'log', 'cyan')
|
||||||
const button = this.page.locator(selector).first()
|
await joinButton.click()
|
||||||
const visible = await button.isVisible().catch(() => false)
|
|
||||||
|
|
||||||
if (visible) {
|
|
||||||
await button.click()
|
|
||||||
await this.humanDelay(2000, 3000)
|
await this.humanDelay(2000, 3000)
|
||||||
await this.waitForPageStable('AFTER_JOIN', 10000)
|
await this.waitForPageStable('AFTER_JOIN', 7000)
|
||||||
joined = true
|
log(false, 'CREATOR', '✅ Successfully clicked Join button', 'log', 'green')
|
||||||
break
|
} else {
|
||||||
}
|
log(false, 'CREATOR', '✅ Already enrolled or Join button not found', 'log', 'gray')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!joined) {
|
log(false, 'CREATOR', '✅ Enrollment process completed', 'log', 'green')
|
||||||
log(false, 'CREATOR', 'Join button not found - may already be enrolled', 'log', 'yellow')
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.waitForPageStable('POST_ENROLLMENT', 10000)
|
|
||||||
await this.humanDelay(2000, 3000)
|
|
||||||
|
|
||||||
// Handle post-enrollment popups
|
|
||||||
await this.humanDelay(2000, 3000)
|
|
||||||
await this.handleRewardsWelcomeTour()
|
|
||||||
await this.humanDelay(2000, 3000)
|
|
||||||
await this.handleRewardsPopups()
|
|
||||||
|
|
||||||
log(false, 'CREATOR', '✅ Rewards enrollment completed', 'log', 'green')
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const msg = error instanceof Error ? error.message : String(error)
|
const msg = error instanceof Error ? error.message : String(error)
|
||||||
|
|||||||
Reference in New Issue
Block a user