store api_id in session file. optional session_key (=api_hash by default) as encryption key

This commit is contained in:
Wizou 2022-01-25 16:37:09 +01:00
parent 6ff0dc40ed
commit 733d106265
5 changed files with 32 additions and 21 deletions

View file

@ -23,7 +23,7 @@ static async Task Main(string[] _)
Console.WriteLine($"We are logged-in as {user.username ?? user.first_name + " " + user.last_name} (id {user.id})");
}
```
When run, this will prompt you interactively for your App **api_id** and **api_hash** (that you obtain through Telegram's [API development tools](https://my.telegram.org/apps) page) and try to connect to Telegram servers.
When run, this will prompt you interactively for your App **api_hash** and **api_id** (that you obtain through Telegram's [API development tools](https://my.telegram.org/apps) page) and try to connect to Telegram servers.
Then it will attempt to sign-in *(login)* as a user for which you must enter the **phone_number** and the **verification_code** that will be sent to this user (for example through SMS or another Telegram client app the user is connected to).
@ -33,7 +33,7 @@ And that's it, you now have access to the **[full range of Telegram Client APIs]
All those API methods are available *(with an underscore in the method name, instead of a dot)*, like this: `await client.Method_Name(...)`
# Saved session
If you run this program again, you will notice that only **api_id** and **api_hash** are requested, the other prompts are gone and you are automatically logged-on and ready to go.
If you run this program again, you will notice that only **api_hash** is requested, the other prompts are gone and you are automatically logged-on and ready to go.
This is because WTelegramClient saves (typically in the encrypted file **bin\WTelegram.session**) its state and the authentication keys that were negociated with Telegram so that you needn't sign-in again every time.
@ -127,7 +127,7 @@ The Client class also offers an `Update` event that is triggered when Telegram s
An invalid API request can result in a `RpcException` being raised, reflecting the [error code and status text](https://revgram.github.io/errors.html) of the problem.
The other configuration items that you can override include: **session_pathname, server_address, device_model, system_version, app_version, system_lang_code, lang_pack, lang_code, user_id**
The other configuration items that you can override include: **session_pathname, session_key, server_address, device_model, system_version, app_version, system_lang_code, lang_pack, lang_code, user_id**
Optional API parameters have a default value of `null` when unset. Passing `null` for a required string/array is the same as *empty* (0-length). Required API parameters/fields can sometimes be set to 0 or `null` when unused (check API documentation or experiment).

View file

@ -50,9 +50,8 @@ namespace WTelegram
public delegate void ProgressCallback(long transmitted, long totalSize);
private readonly Func<string, string> _config;
private readonly int _apiId;
private readonly string _apiHash;
private readonly Session _session;
private string _apiHash;
private Session.DCSession _dcSession;
private TcpClient _tcpClient;
private Stream _networkStream;
@ -89,9 +88,10 @@ namespace WTelegram
public Client(Func<string, string> configProvider = null)
{
_config = configProvider ?? DefaultConfigOrAsk;
_apiId = int.Parse(Config("api_id"));
_apiHash = Config("api_hash");
_session = Session.LoadOrCreate(Config("session_pathname"), Convert.FromHexString(_apiHash));
var session_pathname = Config("session_pathname");
var session_key = _config("session_key") ?? (_apiHash = Config("api_hash"));
_session = Session.LoadOrCreate(session_pathname, Convert.FromHexString(session_key));
if (_session.ApiId == 0) _session.ApiId = int.Parse(Config("api_id"));
if (_session.MainDC != 0) _session.DCSessions.TryGetValue(_session.MainDC, out _dcSession);
_dcSession ??= new() { Id = Helpers.RandomLong() };
_dcSession.Client = this;
@ -102,8 +102,6 @@ namespace WTelegram
private Client(Client cloneOf, Session.DCSession dcSession)
{
_config = cloneOf._config;
_apiId = cloneOf._apiId;
_apiHash = cloneOf._apiHash;
_session = cloneOf._session;
TcpHandler = cloneOf.TcpHandler;
MTProxyUrl = cloneOf.MTProxyUrl;
@ -127,8 +125,8 @@ namespace WTelegram
"server_address" => "149.154.167.50:443", // DC 2
#endif
"device_model" => Environment.Is64BitOperatingSystem ? "PC 64bit" : "PC 32bit",
"system_version" => System.Runtime.InteropServices.RuntimeInformation.OSDescription,
"app_version" => (Assembly.GetEntryAssembly() ?? AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.EntryPoint != null))?.GetName().Version.ToString() ?? "0.0",
"system_version" => Helpers.GetSystemVersion(),
"app_version" => Helpers.GetAppVersion(),
"system_lang_code" => CultureInfo.InstalledUICulture.TwoLetterISOLanguageName,
"lang_pack" => "",
"lang_code" => CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
@ -141,7 +139,8 @@ namespace WTelegram
private static string AskConfig(string config)
{
if (config == "api_id") Console.WriteLine("Welcome! You can obtain your api_id/api_hash at https://my.telegram.org/apps");
if (config == "session_key") return null;
if (config == "api_hash") Console.WriteLine("Welcome! You can obtain your api_id/api_hash at https://my.telegram.org/apps");
Console.Write($"Enter {config.Replace('_', ' ')}: ");
return Console.ReadLine();
}
@ -340,7 +339,7 @@ namespace WTelegram
TLConfig = await this.InvokeWithLayer(Layer.Version,
new TL.Methods.InitConnection<Config>
{
api_id = _apiId,
api_id = _session.ApiId,
device_model = Config("device_model"),
system_version = Config("system_version"),
app_version = Config("app_version"),
@ -1082,7 +1081,7 @@ namespace WTelegram
await this.Auth_LogOut();
_session.UserId = _dcSession.UserId = 0;
}
var authorization = await this.Auth_ImportBotAuthorization(0, _apiId, _apiHash, botToken);
var authorization = await this.Auth_ImportBotAuthorization(0, _session.ApiId, _apiHash ??= Config("api_hash"), botToken);
return LoginAlreadyDone(authorization);
}
@ -1122,11 +1121,11 @@ namespace WTelegram
Auth_SentCode sentCode;
try
{
sentCode = await this.Auth_SendCode(phone_number, _apiId, _apiHash, settings ??= new());
sentCode = await this.Auth_SendCode(phone_number, _session.ApiId, _apiHash ??= Config("api_hash"), settings ??= new());
}
catch (RpcException ex) when (ex.Code == 500 && ex.Message == "AUTH_RESTART")
{
sentCode = await this.Auth_SendCode(phone_number, _apiId, _apiHash, settings ??= new());
sentCode = await this.Auth_SendCode(phone_number, _session.ApiId, _apiHash, settings);
}
resent:
var timeout = DateTime.UtcNow + TimeSpan.FromSeconds(sentCode.timeout);

View file

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Numerics;
using System.Reflection;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
@ -253,6 +254,16 @@ namespace WTelegram
0x3f, 0x00
};
internal static string GetSystemVersion()
{
var os = System.Runtime.InteropServices.RuntimeInformation.OSDescription;
int space = os.IndexOf(' ') + 1, dot = os.IndexOf('.');
return os[(os.IndexOf(' ', space) < 0 ? 0 : space)..(dot < 0 ? os.Length : dot)];
}
internal static string GetAppVersion()
=> (Assembly.GetEntryAssembly() ?? Array.Find(AppDomain.CurrentDomain.GetAssemblies(), a => a.EntryPoint != null))?.GetName().Version.ToString() ?? "0.0";
public class IndirectStream : Stream
{
public IndirectStream(Stream innerStream) => _innerStream = innerStream;

View file

@ -11,6 +11,7 @@ namespace WTelegram
{
internal class Session
{
public int ApiId;
public long UserId;
public int MainDC;
public Dictionary<int, DCSession> DCSessions = new();

View file

@ -5572,9 +5572,9 @@ namespace TL
/// <summary>App version</summary>
public string app_version;
/// <summary>When was the session created</summary>
public int date_created;
public DateTime date_created;
/// <summary>When was the session last active</summary>
public int date_active;
public DateTime date_active;
/// <summary>Last known IP</summary>
public string ip;
/// <summary>Country determined from IP</summary>
@ -9542,9 +9542,9 @@ namespace TL
/// <summary>Platform</summary>
public string platform;
/// <summary>When was the web session created</summary>
public int date_created;
public DateTime date_created;
/// <summary>When was the web session last active</summary>
public int date_active;
public DateTime date_active;
/// <summary>IP address</summary>
public string ip;
/// <summary>Region, determined from IP address</summary>