From f327c27b306bf925d1d198e4318ad952e2e4ae2f Mon Sep 17 00:00:00 2001 From: M3gA-Mind Date: Fri, 30 Jan 2026 20:47:03 +0530 Subject: [PATCH] Refactor Telegram authentication flow to prevent interference during QR login and DC migration - Introduced flags to track the QR flow and DC migration states, preventing polling and authentication checks during sensitive operations. - Updated polling intervals and added initial delays to enhance the user experience during authentication. - Improved code clarity with detailed comments explaining the new flow control mechanisms. This update ensures a smoother and more reliable authentication process for users, reducing the risk of errors during critical operations. --- src/components/TelegramConnectionModal.tsx | 30 +++++++++++-- src/services/mtprotoService.ts | 52 ++++++++++++++++++---- src/store/telegram/thunks.ts | 9 ++++ 3 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/components/TelegramConnectionModal.tsx b/src/components/TelegramConnectionModal.tsx index f3e0d1cec..a17b43252 100644 --- a/src/components/TelegramConnectionModal.tsx +++ b/src/components/TelegramConnectionModal.tsx @@ -325,7 +325,9 @@ const TelegramConnectionModal = ({ return () => clearInterval(interval); }, [qrCodeExpires, currentStep, isAuthenticating, startQrCodeFlow]); - // Poll authentication status every 5 seconds when QR code is displayed + // Poll authentication status when QR code is displayed + // IMPORTANT: Polling is disabled during active QR flow to prevent interference + // with the signInWithQrCode authentication process and DC migration useEffect(() => { if (currentStep !== "qr" || !qrCodeUrl || isAuthenticating) { return; @@ -334,10 +336,25 @@ const TelegramConnectionModal = ({ const pollAuthStatus = async () => { try { if (!mtprotoService.isReady()) return; + + // CRITICAL: Don't poll if QR flow or DC migration is in progress + // This prevents the infinite reconnection loop caused by concurrent + // calls to checkAuthorization() during sensitive operations + if (mtprotoService.shouldBlockExternalCalls()) { + console.debug("Skipping auth poll - QR flow or DC migration in progress"); + return; + } + const client = mtprotoService.getClient(); const isAuthorized = await client.checkAuthorization(); if (isAuthorized) { + // Double-check we're still not in a sensitive state after the async call + if (mtprotoService.shouldBlockExternalCalls()) { + console.debug("Skipping auth completion - flow state changed"); + return; + } + try { const me = await client.getMe(); if (!user) { @@ -383,10 +400,15 @@ const TelegramConnectionModal = ({ } }; - pollAuthStatus(); - const interval = setInterval(pollAuthStatus, 5000); + // Initial poll after a delay to allow QR flow to start + const initialTimeout = setTimeout(pollAuthStatus, 2000); + // Poll every 10 seconds (increased from 5s to reduce interference) + const interval = setInterval(pollAuthStatus, 10000); - return () => clearInterval(interval); + return () => { + clearTimeout(initialTimeout); + clearInterval(interval); + }; }, [ currentStep, qrCodeUrl, diff --git a/src/services/mtprotoService.ts b/src/services/mtprotoService.ts index 60173e9cc..1567a5a10 100644 --- a/src/services/mtprotoService.ts +++ b/src/services/mtprotoService.ts @@ -34,6 +34,10 @@ class MTProtoService { // QR login race condition guard private isScanningComplete = false; + // More reliable flag that tracks the entire QR flow lifecycle + private isQrFlowInProgress = false; + // DC migration tracking to prevent interference during migration + private isDcMigrating = false; private constructor() { // Private constructor to enforce singleton @@ -203,8 +207,10 @@ class MTProtoService { ); } - // Reset race condition guard + // Reset race condition guards and set flow in progress this.isScanningComplete = false; + this.isQrFlowInProgress = true; + this.isDcMigrating = false; try { const user = await this.client.signInUserWithQrCode( @@ -243,11 +249,16 @@ class MTProtoService { const errorMessage = err.message || ""; // DC migration — the library handles this internally but we - // notify the UI for status display - if (errorMessage.includes("NETWORK_MIGRATE_")) { - const dcMatch = errorMessage.match(/NETWORK_MIGRATE_(\d+)/); + // notify the UI for status display and set migration flag + if (errorMessage.includes("NETWORK_MIGRATE_") || errorMessage.includes("MIGRATE_")) { + const dcMatch = errorMessage.match(/(?:NETWORK_)?MIGRATE_(\d+)/); if (dcMatch) { + this.isDcMigrating = true; onStatus?.({ type: "dc_migration", dcId: Number(dcMatch[1]) }); + // Clear migration flag after a delay to allow migration to complete + setTimeout(() => { + this.isDcMigrating = false; + }, 10000); } // Don't stop — let the library handle DC migration return false; @@ -280,8 +291,10 @@ class MTProtoService { }, ); - // Mark scanning as complete + // Mark scanning as complete and clear flow flag this.isScanningComplete = true; + this.isQrFlowInProgress = false; + this.isDcMigrating = false; onStatus?.({ type: "scanning_complete" }); // Save session after successful login (critical after DC migration @@ -297,6 +310,8 @@ class MTProtoService { return user; } catch (error) { this.isScanningComplete = true; + this.isQrFlowInProgress = false; + this.isDcMigrating = false; const errorMessage = error instanceof Error ? error.message : String(error); @@ -317,11 +332,28 @@ class MTProtoService { } /** - * Check if QR scanning is still in progress (not yet complete or errored). - * Use this to avoid starting a new QR flow while one is active. + * Check if QR login flow is in progress. + * Use this to prevent external operations (like polling) from interfering + * with the active authentication flow. */ isQrScanningActive(): boolean { - return !this.isScanningComplete; + return this.isQrFlowInProgress; + } + + /** + * Check if DC migration is in progress. + * During DC migration, external calls to the client can corrupt state. + */ + isDcMigrationInProgress(): boolean { + return this.isDcMigrating; + } + + /** + * Check if any sensitive operation is in progress that should block polling. + * This includes QR flow and DC migration. + */ + shouldBlockExternalCalls(): boolean { + return this.isQrFlowInProgress || this.isDcMigrating; } /** @@ -449,6 +481,10 @@ class MTProtoService { this.initializePromise = null; this.connectPromise = null; this.checkConnectionPromise = null; + // Reset QR flow flags + this.isScanningComplete = false; + this.isQrFlowInProgress = false; + this.isDcMigrating = false; } /** diff --git a/src/store/telegram/thunks.ts b/src/store/telegram/thunks.ts index d3befc949..c31b7972b 100644 --- a/src/store/telegram/thunks.ts +++ b/src/store/telegram/thunks.ts @@ -55,6 +55,15 @@ export const checkAuthStatus = createAsyncThunk( ); } + // CRITICAL: Don't check auth status if QR flow or DC migration is in progress + // This prevents interference with the active authentication flow + if (mtprotoService.shouldBlockExternalCalls()) { + console.debug("checkAuthStatus skipped - QR flow or DC migration in progress"); + const state = getState() as RootState; + const u = state.telegram.byUser[userId]; + return (u?.currentUser as TelegramUser) || null; + } + const now = Date.now(); if (isCheckingAuth && now - lastCheckTime < MIN_CHECK_INTERVAL) { const state = getState() as RootState;