@@ -173,7 +173,20 @@ private void newClient()
173173 {
174174 _logger . LogDebug ( ex , "Could not snapshot the session file" ) ;
175175 }
176- client = new WTelegram . Client ( Convert . ToInt32 ( GeneralConfigStatic . tlconfig ? . api_id ?? Environment . GetEnvironmentVariable ( "api_id" ) ) , GeneralConfigStatic . tlconfig ? . hash_id ?? Environment . GetEnvironmentVariable ( "hash_id" ) , UserService . USERDATAFOLDER + "/WTelegram.session" ) ;
176+ string apiId = GeneralConfigStatic . tlconfig ? . api_id ?? Environment . GetEnvironmentVariable ( "api_id" ) ;
177+ string apiHash = GeneralConfigStatic . tlconfig ? . hash_id ?? Environment . GetEnvironmentVariable ( "hash_id" ) ;
178+ // Custom config callback instead of the convenience constructor: the
179+ // QR login flow (LoginWithQRCode) asks for the 2FA password through
180+ // Config("password") - with the default config that prompt would go
181+ // to the console. Route it to the web UI instead.
182+ client = new WTelegram . Client ( what => what switch
183+ {
184+ "api_id" => apiId ,
185+ "api_hash" => apiHash ,
186+ "session_pathname" => UserService . USERDATAFOLDER + "/WTelegram.session" ,
187+ "password" => RequestLoginPassword ( ) ,
188+ _ => null
189+ } ) ;
177190 ApplyConfiguredParallelTransfers ( client ) ;
178191 if ( GeneralConfigStatic . config . ShouldShowLogInTerminal )
179192 {
@@ -585,9 +598,41 @@ async Task GuardedWorker(WTelegram.Client pc)
585598
586599 #endregion
587600
601+ // 2FA password bridge for the QR login flow: WTelegram asks for the
602+ // password via Config("password") on a background task; the UI is
603+ // notified through QrPasswordNeeded and supplies the value with
604+ // ProvideQrLoginPassword, unblocking the pending request.
605+ private static TaskCompletionSource < string > qrPasswordRequest ;
606+ public static event EventHandler QrPasswordNeeded ;
607+
608+ private static string RequestLoginPassword ( )
609+ {
610+ TaskCompletionSource < string > tcs = new TaskCompletionSource < string > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
611+ qrPasswordRequest = tcs ;
612+ try
613+ {
614+ QrPasswordNeeded ? . Invoke ( null , EventArgs . Empty ) ;
615+ }
616+ catch ( Exception )
617+ {
618+ }
619+ // Blocks the QR login background task, never the UI thread.
620+ if ( ! tcs . Task . Wait ( TimeSpan . FromMinutes ( 5 ) ) )
621+ throw new TimeoutException ( "2FA password was not provided in time" ) ;
622+ return tcs . Task . Result ;
623+ }
624+
625+ public void ProvideQrLoginPassword ( string password )
626+ {
627+ qrPasswordRequest ? . TrySetResult ( password ) ;
628+ }
629+
588630 public async Task < User > CallQrGenerator ( Action < string > func , CancellationToken ct , bool logoutFirst = false )
589631 {
590- return await client . LoginWithQRCode ( func , logoutFirst : logoutFirst , ct : ct ) ;
632+ User user = await client . LoginWithQRCode ( func , logoutFirst : logoutFirst , ct : ct ) ;
633+ if ( user != null )
634+ await CompleteLogin ( ) ;
635+ return user ;
591636 }
592637
593638 public async Task < User > GetUser ( )
@@ -632,6 +677,16 @@ async Task<string> DoLogin(string loginInfo) // (add this method to your code)
632677 return "pass" ; // if user has enabled 2FA
633678 default : break ;
634679 }
680+ return await CompleteLogin ( ) ;
681+ }
682+
683+ /// <summary>
684+ /// Post-login initialization shared by the interactive login flow and the
685+ /// QR login flow: loads chats, resolves premium limits and notifies
686+ /// subscribers.
687+ /// </summary>
688+ private async Task < string > CompleteLogin ( )
689+ {
635690 await getAllChats ( ) ;
636691 SetSplitSizeGB ( ) ;
637692 if ( client . User . flags . HasFlag ( User . Flags . premium ) )
@@ -696,8 +751,20 @@ public async Task<string> checkAuth(string number, bool isPhone = false)
696751 }
697752 else
698753 {
699- _logger . LogInformation ( "No saved user data found, requesting phone" ) ;
700- return "phone" ;
754+ // No saved phone (e.g. the session was created via QR login):
755+ // try to restore the session directly - Login(null) completes
756+ // silently when the stored session is still authorized and
757+ // returns the "phone" step otherwise.
758+ try
759+ {
760+ _logger . LogInformation ( "No saved user data found, attempting session restore" ) ;
761+ return await DoLogin ( null ) ?? "phone" ;
762+ }
763+ catch ( Exception ex )
764+ {
765+ _logger . LogWarning ( ex , "Session restore without saved user data failed, requesting phone" ) ;
766+ return "phone" ;
767+ }
701768 }
702769
703770 }
0 commit comments