mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-10 17:26:17 +00:00
Added an automatic escape manager to close native system dialogs upon login
This commit is contained in:
@@ -228,6 +228,9 @@ export class Login {
|
|||||||
|
|
||||||
await this.disableFido(page)
|
await this.disableFido(page)
|
||||||
|
|
||||||
|
// CRITICAL: Start automatic Escape sender to dismiss native OS dialogs
|
||||||
|
this.passkeyHandler.startEscapeWatcher(page)
|
||||||
|
|
||||||
const [reloadResult, totpResult, portalCheck] = await Promise.allSettled([
|
const [reloadResult, totpResult, portalCheck] = await Promise.allSettled([
|
||||||
this.bot.browser.utils.reloadBadPage(page),
|
this.bot.browser.utils.reloadBadPage(page),
|
||||||
this.totpHandler.tryAutoTotp(page, 'initial landing'),
|
this.totpHandler.tryAutoTotp(page, 'initial landing'),
|
||||||
@@ -258,7 +261,13 @@ export class Login {
|
|||||||
await saveSessionData(this.bot.config.sessionPath, page.context(), email, this.bot.isMobile)
|
await saveSessionData(this.bot.config.sessionPath, page.context(), email, this.bot.isMobile)
|
||||||
this.bot.log(this.bot.isMobile, 'LOGIN', 'Login complete')
|
this.bot.log(this.bot.isMobile, 'LOGIN', 'Login complete')
|
||||||
this.totpHandler.setTotpSecret(undefined)
|
this.totpHandler.setTotpSecret(undefined)
|
||||||
|
|
||||||
|
// Stop Escape watcher after successful login
|
||||||
|
this.passkeyHandler.stopEscapeWatcher()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
// Stop Escape watcher on error
|
||||||
|
this.passkeyHandler.stopEscapeWatcher()
|
||||||
|
|
||||||
const errorMessage = e instanceof Error ? e.message : String(e)
|
const errorMessage = e instanceof Error ? e.message : String(e)
|
||||||
const stackTrace = e instanceof Error ? e.stack : undefined
|
const stackTrace = e instanceof Error ? e.stack : undefined
|
||||||
this.bot.log(this.bot.isMobile, 'LOGIN', `Failed login: ${errorMessage}${stackTrace ? '\nStack: ' + stackTrace.split('\n').slice(0, 3).join(' | ') : ''}`, 'error')
|
this.bot.log(this.bot.isMobile, 'LOGIN', `Failed login: ${errorMessage}${stackTrace ? '\nStack: ' + stackTrace.split('\n').slice(0, 3).join(' | ') : ''}`, 'error')
|
||||||
|
|||||||
@@ -31,55 +31,40 @@ export class PasskeyHandler {
|
|||||||
}).catch(logError('LOGIN-FIDO', 'Route interception setup failed', this.bot.isMobile))
|
}).catch(logError('LOGIN-FIDO', 'Route interception setup failed', this.bot.isMobile))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private escapeWatcherInterval: NodeJS.Timeout | null = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup dialog handlers to automatically dismiss native browser dialogs
|
* Start automatic Escape key sender to dismiss native OS dialogs (Bluetooth, Windows Hello)
|
||||||
* CRITICAL: This handles Bluetooth/Windows Hello/Passkey prompts that appear as native browser dialogs
|
* CRITICAL: Native system dialogs cannot be dismissed via Playwright dialog handlers
|
||||||
* These are NOT DOM elements and cannot be clicked - they must be dismissed via page.on('dialog')
|
* They can only be closed with Escape key (as user discovered)
|
||||||
*/
|
*/
|
||||||
public setupDialogHandlers(page: Page) {
|
public startEscapeWatcher(page: Page) {
|
||||||
// Remove any existing listeners to prevent duplicates
|
// Stop any existing watcher
|
||||||
page.removeAllListeners('dialog')
|
this.stopEscapeWatcher()
|
||||||
|
|
||||||
page.on('dialog', async (dialog) => {
|
this.bot.log(this.bot.isMobile, 'LOGIN-ESCAPE', 'Starting automatic Escape sender (500ms interval)', 'log', 'cyan')
|
||||||
const message = dialog.message()
|
|
||||||
const type = dialog.type()
|
|
||||||
|
|
||||||
this.bot.log(
|
this.escapeWatcherInterval = setInterval(async () => {
|
||||||
this.bot.isMobile,
|
|
||||||
'LOGIN-DIALOG',
|
|
||||||
`Native browser dialog detected: [${type}] "${message.substring(0, 100)}"`,
|
|
||||||
'warn'
|
|
||||||
)
|
|
||||||
|
|
||||||
// Auto-dismiss all dialogs (alert, confirm, prompt, beforeunload)
|
|
||||||
// For passkey/Bluetooth prompts, we want to DISMISS (equivalent to Cancel)
|
|
||||||
try {
|
try {
|
||||||
if (type === 'beforeunload') {
|
// Send Escape key to dismiss any native dialogs
|
||||||
// Accept beforeunload to allow navigation
|
await page.keyboard.press('Escape').catch(() => {
|
||||||
await dialog.accept()
|
// Silent failure - page might be closed
|
||||||
this.bot.log(this.bot.isMobile, 'LOGIN-DIALOG', 'Accepted beforeunload dialog', 'log', 'green')
|
})
|
||||||
} else {
|
} catch {
|
||||||
// Dismiss all other dialogs (passkey, Bluetooth, alerts)
|
// Silent failure - interval will be cleared when stopEscapeWatcher is called
|
||||||
await dialog.dismiss()
|
|
||||||
this.bot.log(
|
|
||||||
this.bot.isMobile,
|
|
||||||
'LOGIN-DIALOG',
|
|
||||||
`Dismissed ${type} dialog: "${message.substring(0, 50)}"`,
|
|
||||||
'log',
|
|
||||||
'green'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
this.bot.log(
|
|
||||||
this.bot.isMobile,
|
|
||||||
'LOGIN-DIALOG',
|
|
||||||
`Failed to handle dialog: ${error instanceof Error ? error.message : String(error)}`,
|
|
||||||
'error'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
})
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
this.bot.log(this.bot.isMobile, 'LOGIN-DIALOG', 'Dialog handlers installed (auto-dismiss enabled)', 'log', 'cyan')
|
/**
|
||||||
|
* Stop the automatic Escape key sender
|
||||||
|
*/
|
||||||
|
public stopEscapeWatcher() {
|
||||||
|
if (this.escapeWatcherInterval) {
|
||||||
|
clearInterval(this.escapeWatcherInterval)
|
||||||
|
this.escapeWatcherInterval = null
|
||||||
|
this.bot.log(this.bot.isMobile, 'LOGIN-ESCAPE', 'Stopped automatic Escape sender', 'log', 'cyan')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handlePasskeyPrompts(page: Page, context: 'main' | 'oauth') {
|
public async handlePasskeyPrompts(page: Page, context: 'main' | 'oauth') {
|
||||||
|
|||||||
Reference in New Issue
Block a user