diff --git a/src/bot/authProcedure.ts b/src/bot/authProcedure.ts index b7f6953..a895450 100644 --- a/src/bot/authProcedure.ts +++ b/src/bot/authProcedure.ts @@ -36,11 +36,21 @@ export class AuthProcedure { try { this._logger.info(`Authenticating as ${email}...`); - // Navigate to Microsoft login - await this._page.goto(_LOGIN_URL, { - waitUntil: 'domcontentloaded', - timeout: 30000, - }); + // Only navigate to login page if not already there. + // When called after clicking "Sign in" on Teams pre-join page, + // the browser is already on login.microsoftonline.com WITH a return URL + // embedded by Teams. Navigating again would destroy that return URL! + const currentUrl = this._page.url(); + if (!currentUrl.includes('login.microsoftonline.com')) { + this._logger.info('Not on login page yet, navigating to Microsoft login...'); + await this._page.goto(_LOGIN_URL, { + waitUntil: 'domcontentloaded', + timeout: 30000, + }); + } else { + this._logger.info('Already on Microsoft login page - skipping navigation to preserve return URL'); + await this._page.waitForLoadState('domcontentloaded', { timeout: 15000 }); + } // Wait for email input const emailInput = await this._page.waitForSelector( diff --git a/src/bot/orchestrator.ts b/src/bot/orchestrator.ts index 897381b..386ce4d 100644 --- a/src/bot/orchestrator.ts +++ b/src/bot/orchestrator.ts @@ -214,32 +214,57 @@ export class BotOrchestrator { if (authSuccess) { this._logger.info('Authentication via "Sign in" link succeeded'); - // After login, Teams does a redirect chain automatically: - // Login → M365 → Teams v2 → Pre-Join page (/v2/) - // Do NOT navigate anywhere. Just wait for the redirect chain to complete - // and for the "Join now" button to appear on the Teams v2 pre-join page. - this._logger.info('Waiting for Teams to redirect to authenticated pre-join page...'); + // After login, the redirect chain goes automatically: + // login.microsoftonline.com → teams.microsoft.com/v2/?meetingjoin=true#/meet/... + // The return URL is embedded by Teams when clicking "Sign in". + // We just wait for the redirect to complete. + this._logger.info('Waiting for redirect chain to leave login.microsoftonline.com...'); - // Wait for the #prejoin-join-button to appear (up to 30 seconds) - // This button only exists on the Teams v2 authenticated pre-join page + // Step 1: Wait for URL to leave login.microsoftonline.com (poll up to 45s) + const maxWaitMs = 45000; + const pollIntervalMs = 1000; + const startTime = Date.now(); + let leftLoginPage = false; + + while (Date.now() - startTime < maxWaitMs) { + const currentUrl = this._page!.url(); + if (!currentUrl.includes('login.microsoftonline.com')) { + this._logger.info(`Left login page after ${Date.now() - startTime}ms. URL: ${currentUrl.substring(0, 100)}`); + leftLoginPage = true; + break; + } + await this._page!.waitForTimeout(pollIntervalMs); + } + + if (!leftLoginPage) { + const stuckUrl = this._page!.url(); + this._logger.warn(`Still on login page after ${maxWaitMs}ms. URL: ${stuckUrl.substring(0, 100)}`); + // Try navigating to meeting URL as fallback (auth cookies should be set) + this._logger.info('Fallback: navigating to meeting URL with auth cookies...'); + await this._page!.goto(this._meetingUrl, { waitUntil: 'domcontentloaded', timeout: 30000 }); + await this._joinProcedure!.handleLauncherIfPresent(); + } + + // Step 2: Wait for the pre-join page to fully load + // The #prejoin-join-button appears on the Teams v2 authenticated pre-join page const joinButtonSelector = '#prejoin-join-button, button[data-tid="prejoin-join-button"]'; try { await this._page!.waitForSelector(joinButtonSelector, { timeout: 30000, state: 'visible' }); - const currentUrl = this._page!.url(); - this._logger.info(`Arrived at authenticated pre-join page: ${currentUrl.substring(0, 80)}`); + const finalUrl = this._page!.url(); + this._logger.info(`On authenticated pre-join page: ${finalUrl.substring(0, 100)}`); } catch { - const currentUrl = this._page!.url(); + const finalUrl = this._page!.url(); const pageContent = await this._page!.evaluate(() => document.body?.innerText?.substring(0, 300) || ''); - this._logger.warn(`Join button not found after auth redirect. URL: ${currentUrl.substring(0, 80)}`); + this._logger.warn(`Join button not found. URL: ${finalUrl.substring(0, 100)}`); this._logger.warn(`Page content: ${pageContent.substring(0, 200)}`); - } - - // Verify we're on the authenticated pre-join page - const pageText = await this._page!.evaluate(() => document.body?.innerText?.substring(0, 500) || ''); - if (pageText.includes('Join now')) { - this._logger.info('On authenticated pre-join page with "Join now" button'); - } else { - this._logger.warn(`Post-auth page content: ${pageText.substring(0, 300)}`); + + // If we ended up somewhere unexpected, try meeting URL as last resort + if (!finalUrl.includes('teams.microsoft.com')) { + this._logger.info('Not on Teams - navigating to meeting URL as last resort...'); + await this._page!.goto(this._meetingUrl, { waitUntil: 'domcontentloaded', timeout: 30000 }); + await this._joinProcedure!.handleLauncherIfPresent(); + await this._page!.waitForTimeout(5000); + } } } else { this._logger.warn('Authentication via "Sign in" failed - continuing as anonymous');