mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-11 09:46:16 +00:00
Everything works, creator account mode.
This commit is contained in:
@@ -998,8 +998,8 @@ export class AccountCreator {
|
|||||||
private async handleEmailTaken(retryCount = 0): Promise<{ success: boolean; email: string | null }> {
|
private async handleEmailTaken(retryCount = 0): Promise<{ success: boolean; email: string | null }> {
|
||||||
log(false, 'CREATOR', 'Email taken, looking for Microsoft suggestions...', 'log', 'yellow')
|
log(false, 'CREATOR', 'Email taken, looking for Microsoft suggestions...', 'log', 'yellow')
|
||||||
|
|
||||||
await this.humanDelay(2000, 3000)
|
await this.humanDelay(1000, 1500) // REDUCED: Faster suggestion handling (was 2000-3000)
|
||||||
await this.waitForPageStable('EMAIL_SUGGESTIONS', 10000)
|
await this.waitForPageStable('EMAIL_SUGGESTIONS', 5000) // REDUCED: Faster suggestion detection (was 10000)
|
||||||
|
|
||||||
// Multiple selectors for suggestions container
|
// Multiple selectors for suggestions container
|
||||||
const suggestionSelectors = [
|
const suggestionSelectors = [
|
||||||
@@ -1115,7 +1115,7 @@ export class AccountCreator {
|
|||||||
|
|
||||||
// Click the suggestion
|
// Click the suggestion
|
||||||
await firstButton.click()
|
await firstButton.click()
|
||||||
await this.humanDelay(1500, 2500)
|
await this.humanDelay(500, 1000) // REDUCED: Faster suggestion click (was 1500-2500)
|
||||||
|
|
||||||
// Verify the email input was updated
|
// Verify the email input was updated
|
||||||
const emailInput = this.page.locator('input[type="email"]').first()
|
const emailInput = this.page.locator('input[type="email"]').first()
|
||||||
@@ -1497,6 +1497,9 @@ export class AccountCreator {
|
|||||||
const names = this.dataGenerator.generateNames(email)
|
const names = this.dataGenerator.generateNames(email)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// CRITICAL: Uncheck marketing opt-in BEFORE filling names (checkbox is default checked in US locale)
|
||||||
|
await this.uncheckMarketingOptIn()
|
||||||
|
|
||||||
await this.humanDelay(1000, 2000)
|
await this.humanDelay(1000, 2000)
|
||||||
|
|
||||||
const firstNameSelectors = [
|
const firstNameSelectors = [
|
||||||
@@ -1590,9 +1593,6 @@ export class AccountCreator {
|
|||||||
|
|
||||||
log(false, 'CREATOR', `✅ Names filled: ${names.firstName} ${names.lastName}`, 'log', 'green')
|
log(false, 'CREATOR', `✅ Names filled: ${names.firstName} ${names.lastName}`, 'log', 'green')
|
||||||
|
|
||||||
// CRITICAL: Uncheck marketing opt-in checkbox (decline promotional emails)
|
|
||||||
await this.uncheckMarketingOptIn()
|
|
||||||
|
|
||||||
// CRITICAL: Verify no errors appeared after filling names
|
// CRITICAL: Verify no errors appeared after filling names
|
||||||
const noErrors = await this.verifyNoErrors()
|
const noErrors = await this.verifyNoErrors()
|
||||||
if (!noErrors) {
|
if (!noErrors) {
|
||||||
@@ -1632,23 +1632,36 @@ export class AccountCreator {
|
|||||||
try {
|
try {
|
||||||
log(false, 'CREATOR', 'Checking for marketing opt-in checkbox...', 'log', 'cyan')
|
log(false, 'CREATOR', 'Checking for marketing opt-in checkbox...', 'log', 'cyan')
|
||||||
|
|
||||||
// Multiple selectors for the marketing checkbox
|
// IMPROVED: Wait for checkbox to be present before checking
|
||||||
|
await this.humanDelay(500, 1000)
|
||||||
|
|
||||||
|
// Multiple selectors for the marketing checkbox (order matters: most specific first)
|
||||||
const checkboxSelectors = [
|
const checkboxSelectors = [
|
||||||
'input#marketingOptIn',
|
'input#marketingOptIn',
|
||||||
'input[data-testid="marketingOptIn"]',
|
'input[data-testid="marketingOptIn"]',
|
||||||
'input[name="marketingOptIn"]',
|
'input[name="marketingOptIn"]',
|
||||||
'input[aria-label*="information, tips, and offers"]'
|
'input[type="checkbox"][aria-label*="information"]',
|
||||||
|
'input[type="checkbox"][aria-label*="conseils"]', // French locale
|
||||||
|
'input[type="checkbox"][aria-label*="offers"]'
|
||||||
]
|
]
|
||||||
|
|
||||||
let checkbox = null
|
let checkbox = null
|
||||||
|
|
||||||
for (const selector of checkboxSelectors) {
|
for (const selector of checkboxSelectors) {
|
||||||
|
try {
|
||||||
const element = this.page.locator(selector).first()
|
const element = this.page.locator(selector).first()
|
||||||
const visible = await element.isVisible().catch(() => false)
|
// CRITICAL: Check if visible AND enabled (not disabled)
|
||||||
if (visible) {
|
const visible = await element.isVisible({ timeout: 2000 }).catch(() => false)
|
||||||
|
const enabled = await element.isEnabled().catch(() => false)
|
||||||
|
|
||||||
|
if (visible && enabled) {
|
||||||
checkbox = element
|
checkbox = element
|
||||||
log(false, 'CREATOR', `Found marketing checkbox with selector: ${selector}`, 'log', 'cyan')
|
log(false, 'CREATOR', `Found marketing checkbox: ${selector}`, 'log', 'cyan')
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
} catch {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkbox) {
|
if (!checkbox) {
|
||||||
@@ -1656,25 +1669,38 @@ export class AccountCreator {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the checkbox is already checked
|
// CRITICAL: Wait for checkbox state to stabilize (US locale defaults to checked)
|
||||||
|
await this.humanDelay(300, 600)
|
||||||
|
|
||||||
|
// Check if the checkbox is currently checked
|
||||||
const isChecked = await checkbox.isChecked().catch(() => false)
|
const isChecked = await checkbox.isChecked().catch(() => false)
|
||||||
|
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
log(false, 'CREATOR', 'Marketing checkbox is checked, unchecking it...', 'log', 'yellow')
|
log(false, 'CREATOR', '⚠️ Marketing checkbox is CHECKED (US locale default) - unchecking now...', 'log', 'yellow')
|
||||||
|
|
||||||
// Click to uncheck
|
// Click to uncheck
|
||||||
await checkbox.click()
|
await checkbox.click()
|
||||||
await this.humanDelay(500, 1000)
|
await this.humanDelay(400, 800)
|
||||||
|
|
||||||
// Verify it was unchecked
|
// CRITICAL: Verify it was actually unchecked
|
||||||
const stillChecked = await checkbox.isChecked().catch(() => true)
|
const stillChecked = await checkbox.isChecked().catch(() => true)
|
||||||
if (!stillChecked) {
|
if (!stillChecked) {
|
||||||
log(false, 'CREATOR', '✅ Marketing opt-in unchecked successfully', 'log', 'green')
|
log(false, 'CREATOR', '✅ Marketing opt-in unchecked successfully', 'log', 'green')
|
||||||
} else {
|
} else {
|
||||||
log(false, 'CREATOR', '⚠️ Failed to uncheck marketing opt-in', 'warn', 'yellow')
|
log(false, 'CREATOR', '⚠️ Failed to uncheck marketing opt-in (still checked)', 'warn', 'yellow')
|
||||||
|
// Retry once
|
||||||
|
log(false, 'CREATOR', '🔄 Retrying uncheck...', 'log', 'cyan')
|
||||||
|
await checkbox.click()
|
||||||
|
await this.humanDelay(400, 800)
|
||||||
|
const finalCheck = await checkbox.isChecked().catch(() => true)
|
||||||
|
if (!finalCheck) {
|
||||||
|
log(false, 'CREATOR', '✅ Marketing opt-in unchecked on retry', 'log', 'green')
|
||||||
|
} else {
|
||||||
|
log(false, 'CREATOR', '❌ Could not uncheck marketing opt-in after retry', 'error')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log(false, 'CREATOR', '✅ Marketing opt-in already unchecked', 'log', 'green')
|
log(false, 'CREATOR', '✅ Marketing opt-in already unchecked (good!)', 'log', 'green')
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1945,13 +1971,13 @@ export class AccountCreator {
|
|||||||
|
|
||||||
log(false, 'CREATOR', '✅ On rewards.bing.com', 'log', 'green')
|
log(false, 'CREATOR', '✅ On rewards.bing.com', 'log', 'green')
|
||||||
|
|
||||||
// Clear cookies on rewards page
|
// CRITICAL: Handle "Get started" popup FIRST (before cookies)
|
||||||
await this.dismissCookieBanner()
|
|
||||||
|
|
||||||
// Handle "Get started" popup (ReferAndEarn)
|
|
||||||
await this.humanDelay(2000, 3000)
|
await this.humanDelay(2000, 3000)
|
||||||
await this.handleGetStartedPopup()
|
await this.handleGetStartedPopup()
|
||||||
|
|
||||||
|
// Then clear cookie banner (after Get started)
|
||||||
|
await this.dismissCookieBanner()
|
||||||
|
|
||||||
// Referral enrollment if needed
|
// Referral enrollment if needed
|
||||||
if (this.referralUrl) {
|
if (this.referralUrl) {
|
||||||
await this.humanDelay(2000, 3000)
|
await this.humanDelay(2000, 3000)
|
||||||
@@ -2214,6 +2240,15 @@ export class AccountCreator {
|
|||||||
await this.humanDelay(2000, 3000)
|
await this.humanDelay(2000, 3000)
|
||||||
await this.waitForPageStable('AFTER_JOIN', 7000)
|
await this.waitForPageStable('AFTER_JOIN', 7000)
|
||||||
log(false, 'CREATOR', '✅ Successfully clicked Join button', 'log', 'green')
|
log(false, 'CREATOR', '✅ Successfully clicked Join button', 'log', 'green')
|
||||||
|
|
||||||
|
// CRITICAL: Verify referral was successful by checking for &new=1 in URL
|
||||||
|
const currentUrl = this.page.url()
|
||||||
|
if (currentUrl.includes('&new=1') || currentUrl.includes('?new=1')) {
|
||||||
|
log(false, 'CREATOR', '✅ Referral successful! URL contains &new=1', 'log', 'green')
|
||||||
|
} else {
|
||||||
|
log(false, 'CREATOR', '⚠️ Warning: URL does not contain &new=1 - referral may not have worked', 'warn', 'yellow')
|
||||||
|
log(false, 'CREATOR', `Current URL: ${currentUrl}`, 'log', 'cyan')
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log(false, 'CREATOR', '✅ Already enrolled or Join button not found', 'log', 'gray')
|
log(false, 'CREATOR', '✅ Already enrolled or Join button not found', 'log', 'gray')
|
||||||
}
|
}
|
||||||
@@ -2487,7 +2522,9 @@ ${JSON.stringify(accountData, null, 2)}`
|
|||||||
|
|
||||||
// Strategy 1: Wait for common TOTP secret selectors
|
// Strategy 1: Wait for common TOTP secret selectors
|
||||||
const secretSelectors = [
|
const secretSelectors = [
|
||||||
'#iTOTP_Secret', // Most common
|
'#iActivationCode span.dirltr.bold', // CORRECT: Secret key in span (lvb5 ysvi...)
|
||||||
|
'#iActivationCode span.bold', // Alternative without dirltr
|
||||||
|
'#iTOTP_Secret', // Legacy selector
|
||||||
'#totpSecret', // Alternative
|
'#totpSecret', // Alternative
|
||||||
'input[name="secret"]', // Input field
|
'input[name="secret"]', // Input field
|
||||||
'input[id*="secret"]', // Partial ID match
|
'input[id*="secret"]', // Partial ID match
|
||||||
@@ -2518,7 +2555,8 @@ ${JSON.stringify(accountData, null, 2)}`
|
|||||||
|
|
||||||
for (const method of methods) {
|
for (const method of methods) {
|
||||||
const value = await method()
|
const value = await method()
|
||||||
const cleaned = value?.trim() || ''
|
// CRITICAL: Remove (non-breaking spaces) and all whitespace
|
||||||
|
const cleaned = value?.replace(/\s+/g, '').replace(/ /g, '').trim() || ''
|
||||||
|
|
||||||
// TOTP secrets are typically 16-32 characters, base32 encoded (A-Z, 2-7)
|
// TOTP secrets are typically 16-32 characters, base32 encoded (A-Z, 2-7)
|
||||||
if (cleaned && cleaned.length >= 16 && cleaned.length <= 64 && /^[A-Z2-7]+$/i.test(cleaned)) {
|
if (cleaned && cleaned.length >= 16 && cleaned.length <= 64 && /^[A-Z2-7]+$/i.test(cleaned)) {
|
||||||
@@ -2558,19 +2596,7 @@ ${JSON.stringify(accountData, null, 2)}`
|
|||||||
|
|
||||||
if (!totpSecret) {
|
if (!totpSecret) {
|
||||||
log(false, 'CREATOR', '❌ Could not find TOTP secret', 'error')
|
log(false, 'CREATOR', '❌ Could not find TOTP secret', 'error')
|
||||||
|
log(false, 'CREATOR', ` Current URL: ${this.page.url()}`, 'log', 'cyan')
|
||||||
// Take screenshot for debugging
|
|
||||||
try {
|
|
||||||
const screenshotPath = path.join(process.cwd(), 'totp-secret-not-found.png')
|
|
||||||
await this.page.screenshot({ path: screenshotPath, fullPage: true })
|
|
||||||
log(false, 'CREATOR', `📸 Screenshot saved to: ${screenshotPath}`, 'log', 'cyan')
|
|
||||||
} catch {
|
|
||||||
log(false, 'CREATOR', '⚠️ Could not save debug screenshot', 'warn')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log page URL for manual check
|
|
||||||
log(false, 'CREATOR', `📍 Current URL: ${this.page.url()}`, 'log', 'cyan')
|
|
||||||
|
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2616,11 +2642,53 @@ ${JSON.stringify(accountData, null, 2)}`
|
|||||||
|
|
||||||
log(false, 'CREATOR', '✅ 2FA enabled!', 'log', 'green')
|
log(false, 'CREATOR', '✅ 2FA enabled!', 'log', 'green')
|
||||||
|
|
||||||
// Extract recovery code
|
// IMPROVED: Extract recovery code from <b> tag with multiple strategies
|
||||||
|
let recoveryCode = ''
|
||||||
|
|
||||||
|
// Strategy 1: Look for <b> tag containing recovery code pattern
|
||||||
|
try {
|
||||||
|
const boldElements = await this.page.locator('b').all()
|
||||||
|
for (const element of boldElements) {
|
||||||
|
const text = await element.textContent().catch(() => '') || ''
|
||||||
|
const match = text.match(/([A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5})/)
|
||||||
|
if (match) {
|
||||||
|
recoveryCode = match[1]!
|
||||||
|
log(false, 'CREATOR', '✅ Found recovery code in <b> tag', 'log', 'green')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Continue to next strategy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy 2: Try legacy selector #NewRecoveryCode
|
||||||
|
if (!recoveryCode) {
|
||||||
|
try {
|
||||||
const recoveryElement = this.page.locator('#NewRecoveryCode').first()
|
const recoveryElement = this.page.locator('#NewRecoveryCode').first()
|
||||||
const recoveryText = await recoveryElement.textContent().catch(() => '') || ''
|
const recoveryText = await recoveryElement.textContent().catch(() => '') || ''
|
||||||
const recoveryMatch = recoveryText.match(/([A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5})/)
|
const recoveryMatch = recoveryText.match(/([A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5})/)
|
||||||
const recoveryCode = recoveryMatch ? recoveryMatch[1] : ''
|
if (recoveryMatch) {
|
||||||
|
recoveryCode = recoveryMatch[1]!
|
||||||
|
log(false, 'CREATOR', '✅ Found recovery code via #NewRecoveryCode', 'log', 'green')
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Continue to next strategy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy 3: Scan entire page content as fallback
|
||||||
|
if (!recoveryCode) {
|
||||||
|
try {
|
||||||
|
const pageContent = await this.page.content().catch(() => '')
|
||||||
|
const match = pageContent.match(/([A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5})/)
|
||||||
|
if (match) {
|
||||||
|
recoveryCode = match[1]!
|
||||||
|
log(false, 'CREATOR', '✅ Found recovery code via page scan', 'log', 'yellow')
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (recoveryCode) {
|
if (recoveryCode) {
|
||||||
log(false, 'CREATOR', `🔐 Recovery Code: ${recoveryCode}`, 'log', 'green')
|
log(false, 'CREATOR', `🔐 Recovery Code: ${recoveryCode}`, 'log', 'green')
|
||||||
|
|||||||
Reference in New Issue
Block a user