mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
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.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user