mirror of
https://github.com/wiz0u/WTelegramClient.git
synced 2026-01-14 20:49:58 +01:00
New method LoginWithQRCode (fix #247)
This commit is contained in:
parent
4381781af8
commit
3c19be32c7
2
.github/dev.yml
vendored
2
.github/dev.yml
vendored
|
|
@ -1,7 +1,7 @@
|
|||
pr: none
|
||||
trigger: [ master ]
|
||||
|
||||
name: 4.0.1-dev.$(Rev:r)
|
||||
name: 4.1.1-dev.$(Rev:r)
|
||||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
|
|
|
|||
2
.github/release.yml
vendored
2
.github/release.yml
vendored
|
|
@ -1,7 +1,7 @@
|
|||
pr: none
|
||||
trigger: none
|
||||
|
||||
name: 4.0.$(Rev:r)
|
||||
name: 4.1.$(Rev:r)
|
||||
|
||||
pool:
|
||||
vmImage: ubuntu-latest
|
||||
|
|
|
|||
116
src/Client.cs
116
src/Client.cs
|
|
@ -1203,19 +1203,7 @@ namespace WTelegram
|
|||
}
|
||||
catch (RpcException e) when (e.Code == 401 && e.Message == "SESSION_PASSWORD_NEEDED")
|
||||
{
|
||||
for (int pwdRetry = 1; authorization == null; pwdRetry++)
|
||||
try
|
||||
{
|
||||
var accountPassword = await this.Account_GetPassword();
|
||||
RaiseUpdates(accountPassword);
|
||||
var checkPasswordSRP = await Check2FA(accountPassword, () => ConfigAsync("password"));
|
||||
authorization = await this.Auth_CheckPassword(checkPasswordSRP);
|
||||
}
|
||||
catch (RpcException pe) when (pe.Code == 400 && pe.Message == "PASSWORD_HASH_INVALID")
|
||||
{
|
||||
Helpers.Log(4, "Wrong password!");
|
||||
if (pwdRetry >= MaxCodePwdAttempts) throw;
|
||||
}
|
||||
authorization = await LoginPasswordNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1248,6 +1236,83 @@ namespace WTelegram
|
|||
return User;
|
||||
}
|
||||
|
||||
/// <summary>Login via QR code</summary>
|
||||
/// <param name="qrDisplay">Callback to display the login url as QR code to the user (<a href="https://www.nuget.org/packages/QRCoder/">QRCoder library</a> can help you)</param>
|
||||
/// <param name="except_ids">(optional) To prevent logging as these user ids</param>
|
||||
/// <param name="logoutFirst">If session is already connected to a user, this method will first log out.<br/>You can also check property <see cref="UserId"/> before calling this method.</param>
|
||||
/// <param name="ct">If you need to abort the method before login is completed</param>
|
||||
/// <returns>Detail about the logged-in user</returns>
|
||||
public async Task<User> LoginWithQRCode(Action<string> qrDisplay, long[] except_ids = null, bool logoutFirst = true, CancellationToken ct = default)
|
||||
{
|
||||
await ConnectAsync();
|
||||
if (logoutFirst && _session.UserId != 0) // a user is already logged-in
|
||||
{
|
||||
await this.Auth_LogOut();
|
||||
_session.UserId = _dcSession.UserId = 0;
|
||||
User = null;
|
||||
}
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
OnUpdates += CatchQRUpdate;
|
||||
try
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
var ltb = await this.Auth_ExportLoginToken(_session.ApiId, _apiHash ??= Config("api_hash"), except_ids);
|
||||
retry:
|
||||
switch (ltb)
|
||||
{
|
||||
case Auth_LoginToken lt:
|
||||
var url = "tg://login?token=" + System.Convert.ToBase64String(lt.token).Replace('/', '_').Replace('+', '-');
|
||||
Helpers.Log(3, $"Waiting for this QR code login to be accepted: " + url);
|
||||
qrDisplay(url);
|
||||
if (lt.expires - DateTime.UtcNow is { Ticks: >= 0 } delay)
|
||||
await Task.WhenAny(Task.Delay(delay, ct), tcs.Task);
|
||||
break;
|
||||
case Auth_LoginTokenMigrateTo ltmt:
|
||||
await MigrateToDC(ltmt.dc_id);
|
||||
ltb = await this.Auth_ImportLoginToken(ltmt.token);
|
||||
goto retry;
|
||||
case Auth_LoginTokenSuccess lts:
|
||||
return LoginAlreadyDone(lts.authorization);
|
||||
}
|
||||
}
|
||||
ct.ThrowIfCancellationRequested();
|
||||
return null;
|
||||
}
|
||||
catch (RpcException e) when (e.Code == 401 && e.Message == "SESSION_PASSWORD_NEEDED")
|
||||
{
|
||||
return LoginAlreadyDone(await LoginPasswordNeeded());
|
||||
}
|
||||
finally
|
||||
{
|
||||
OnUpdates -= CatchQRUpdate;
|
||||
}
|
||||
|
||||
Task CatchQRUpdate(UpdatesBase updates)
|
||||
{
|
||||
if (updates.UpdateList.OfType<UpdateLoginToken>().Any())
|
||||
tcs.TrySetResult(true);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Auth_AuthorizationBase> LoginPasswordNeeded()
|
||||
{
|
||||
for (int pwdRetry = 1; ; pwdRetry++)
|
||||
try
|
||||
{
|
||||
var accountPassword = await this.Account_GetPassword();
|
||||
RaiseUpdates(accountPassword);
|
||||
var checkPasswordSRP = await Check2FA(accountPassword, () => ConfigAsync("password"));
|
||||
return await this.Auth_CheckPassword(checkPasswordSRP);
|
||||
}
|
||||
catch (RpcException pe) when (pe.Code == 400 && pe.Message == "PASSWORD_HASH_INVALID")
|
||||
{
|
||||
Helpers.Log(4, "Wrong password!");
|
||||
if (pwdRetry >= MaxCodePwdAttempts) throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary><b>[Not recommended]</b> You can use this if you have already obtained a login authorization manually</summary>
|
||||
/// <param name="authorization">if this was not a successful Auth_Authorization, an exception is thrown</param>
|
||||
/// <returns>the User that was authorized</returns>
|
||||
|
|
@ -1418,16 +1483,7 @@ namespace WTelegram
|
|||
{
|
||||
if (message != "FILE_MIGRATE_X")
|
||||
{
|
||||
// this is a hack to migrate _dcSession in-place (staying in same Client):
|
||||
Session.DCSession dcSession;
|
||||
lock (_session)
|
||||
dcSession = GetOrCreateDCSession(x, _dcSession.DataCenter.flags);
|
||||
Reset(false, false);
|
||||
_session.MainDC = x;
|
||||
_dcSession.Client = null;
|
||||
_dcSession = dcSession;
|
||||
_dcSession.Client = this;
|
||||
await ConnectAsync();
|
||||
await MigrateToDC(x);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
|
@ -1459,6 +1515,20 @@ namespace WTelegram
|
|||
}
|
||||
}
|
||||
|
||||
private async Task MigrateToDC(int dcId)
|
||||
{
|
||||
// this is a hack to migrate _dcSession in-place (staying in same Client):
|
||||
Session.DCSession dcSession;
|
||||
lock (_session)
|
||||
dcSession = GetOrCreateDCSession(dcId, _dcSession.DataCenter.flags);
|
||||
Reset(false, false);
|
||||
_session.MainDC = dcId;
|
||||
_dcSession.Client = null;
|
||||
_dcSession = dcSession;
|
||||
_dcSession.Client = this;
|
||||
await ConnectAsync();
|
||||
}
|
||||
|
||||
public async Task<T> InvokeAffected<T>(IMethod<T> query, long peerId) where T : Messages_AffectedMessages
|
||||
{
|
||||
var result = await Invoke(query);
|
||||
|
|
|
|||
Loading…
Reference in a new issue