Fix 444 trying to download from a media_only DC with unnegociated AuthKey

This commit is contained in:
Wizou 2021-12-05 07:21:30 +01:00
parent e1132f653b
commit 409cf25619
4 changed files with 40 additions and 23 deletions

View file

@ -58,7 +58,7 @@ static string Config(string what)
using var client = new WTelegram.Client(Config);
```
There are other configuration items that are queried to your method but returning `null` let WTelegramClient choose a default adequate value.
Those shown above are the only ones that have no default values and <u>should be provided</u> by your method.
Those shown above are the only ones that have no default values and should be provided by your method.
Returning `null` for verification_code or password will show a prompt for console apps, or an error otherwise.
Another simple approach is to pass `Environment.GetEnvironmentVariable` as the config callback and define the configuration items as environment variables.

View file

@ -1,6 +1,7 @@
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
@ -343,6 +344,8 @@ namespace WTelegram
if (dcSession.Client != null || dcSession.DataCenter.flags == flags)
return dcSession; // if we have already a session with this DC and we are connected or it is a perfect match, use it
// try to find the most appropriate DcOption for this DC
if ((dcSession?.AuthKeyID ?? 0) == 0) // we will need to negociate an AuthKey => can't use media_only DC
flags &= ~DcOption.Flags.media_only;
var dcOptions = _session.DcOptions.Where(dc => dc.id == dcId).OrderBy(dc => dc.flags ^ flags);
var dcOption = dcOptions.FirstOrDefault() ?? throw new ApplicationException($"Could not find adequate dc_option for DC {dcId}");
dcSession ??= new Session.DCSession { Id = Helpers.RandomLong() }; // create new session only if not already existing
@ -960,11 +963,7 @@ namespace WTelegram
_session.UserId = _dcSession.UserId = 0;
}
var authorization = await this.Auth_ImportBotAuthorization(0, _apiId, _apiHash, botToken);
if (authorization is not Auth_Authorization { user: User user })
throw new ApplicationException("Failed to get Authorization: " + authorization.GetType().Name);
_session.UserId = _dcSession.UserId = user.id;
_session.Save();
return user;
return LoginAlreadyDone(authorization);
}
/// <summary>Login as a user (if not already logged-in).
@ -1010,24 +1009,21 @@ namespace WTelegram
sentCode = await this.Auth_SendCode(phone_number, _apiId, _apiHash, settings ??= new());
}
Helpers.Log(3, $"A verification code has been sent via {sentCode.type.GetType().Name[17..]}");
Auth_AuthorizationBase authorization;
for (int retry = 1; ; retry++)
Auth_AuthorizationBase authorization = null;
for (int retry = 1; authorization == null; retry++)
try
{
var verification_code = Config("verification_code");
authorization = await this.Auth_SignIn(phone_number, sentCode.phone_code_hash, verification_code);
break;
}
catch (RpcException e) when (e.Code == 401 && e.Message == "SESSION_PASSWORD_NEEDED")
{
var accountPassword = await this.Account_GetPassword();
var checkPasswordSRP = Check2FA(accountPassword, () => Config("password"));
authorization = await this.Auth_CheckPassword(checkPasswordSRP);
break;
}
catch (RpcException e) when (e.Code == 400 && e.Message == "PHONE_CODE_INVALID" && retry != 3)
{
continue;
}
if (authorization is Auth_AuthorizationSignUpRequired signUpRequired)
{
@ -1040,6 +1036,18 @@ namespace WTelegram
if (wait > TimeSpan.Zero) await Task.Delay(wait); // we get a FLOOD_WAIT_3 if we SignUp too fast
authorization = await this.Auth_SignUp(phone_number, sentCode.phone_code_hash, first_name, last_name);
}
return LoginAlreadyDone(authorization);
}
/// <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>
/// <remarks>This approach is not recommended because you likely didn't properly handle all aspects of the login process
/// <br/>(transient failures, unnecessary login, 2FA, sign-up required, slowness to respond, verification code resending, encryption key safety, etc..)
/// <br/>Methods <c>LoginUserIfNeeded</c> and <c>LoginBotIfNeeded</c> handle these automatically for you</remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public User LoginAlreadyDone(Auth_AuthorizationBase authorization)
{
if (authorization is not Auth_Authorization { user: User user })
throw new ApplicationException("Failed to get Authorization: " + authorization.GetType().Name);
_session.UserId = _dcSession.UserId = user.id;

View file

@ -6,14 +6,20 @@ using System.Net;
using System.Numerics;
using System.Security.Cryptography;
#if NETCOREAPP2_1_OR_GREATER
namespace WTelegram
{
static class Compat
{
#if NETCOREAPP2_1_OR_GREATER
internal static IPEndPoint IPEndPoint_Parse(string addr) => IPEndPoint.Parse(addr);
internal static BigInteger BigEndianInteger(byte[] value) => new(value, true, true);
internal static IPEndPoint IPEndPoint_Parse(string addr) => IPEndPoint.Parse(addr);
}
}
#else
namespace WTelegram
{
static class Compat
{
internal static BigInteger BigEndianInteger(byte[] value)
{
var data = new byte[value.Length + 1];
@ -68,20 +74,21 @@ namespace WTelegram
rsa.ImportParameters(new RSAParameters { Modulus = m.ToArray(), Exponent = e.ToArray() });
}
}
}
static class Convert
static class Convert
{
internal static string ToHexString(byte[] data) => BitConverter.ToString(data).Replace("-", "");
internal static byte[] FromHexString(string hex)
{
internal static byte[] FromHexString(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = System.Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
#endif
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = System.Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
}
#endif
#if NETSTANDARD2_0
namespace System.Runtime.CompilerServices

View file

@ -336,6 +336,7 @@ namespace TL
public static bool operator !=(Int128 left, Int128 right) { for (int i = 0; i < 16; i++) if (left.raw[i] != right.raw[i]) return true; return false; }
public override bool Equals(object obj) => obj is Int128 other && this == other;
public override int GetHashCode() => HashCode.Combine(raw[0], raw[1]);
public override string ToString() => Convert.ToHexString(raw);
public static implicit operator byte[](Int128 int128) => int128.raw;
}
@ -349,6 +350,7 @@ namespace TL
public static bool operator !=(Int256 left, Int256 right) { for (int i = 0; i < 32; i++) if (left.raw[i] != right.raw[i]) return true; return false; }
public override bool Equals(object obj) => obj is Int256 other && this == other;
public override int GetHashCode() => HashCode.Combine(raw[0], raw[1]);
public override string ToString() => Convert.ToHexString(raw);
public static implicit operator byte[](Int256 int256) => int256.raw;
}