diff --git a/README.md b/README.md
index 7ecb0e6..a140c1d 100644
--- a/README.md
+++ b/README.md
@@ -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 should be provided 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.
diff --git a/src/Client.cs b/src/Client.cs
index e3ca2ea..e84cae9 100644
--- a/src/Client.cs
+++ b/src/Client.cs
@@ -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);
}
/// 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);
+ }
+
+ /// [Not recommended] You can use this if you have already obtained a login authorization manually
+ /// if this was not a successful Auth_Authorization, an exception is thrown
+ /// the User that was authorized
+ /// This approach is not recommended because you likely didn't properly handle all aspects of the login process
+ ///
(transient failures, unnecessary login, 2FA, sign-up required, slowness to respond, verification code resending, encryption key safety, etc..)
+ ///
Methods LoginUserIfNeeded and LoginBotIfNeeded handle these automatically for you
+ [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;
diff --git a/src/Compat.cs b/src/Compat.cs
index 818bb4e..6aa4d0a 100644
--- a/src/Compat.cs
+++ b/src/Compat.cs
@@ -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
diff --git a/src/TL.cs b/src/TL.cs
index 6e5f70e..2d49f30 100644
--- a/src/TL.cs
+++ b/src/TL.cs
@@ -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;
}