From 4174b21a830cacd6209831921d914680058d0282 Mon Sep 17 00:00:00 2001 From: Wizou Date: Mon, 30 Aug 2021 01:31:08 +0200 Subject: [PATCH] Experimental collection of id/access_hash pairs --- src/Client.cs | 37 +++++++++++++++++++++++++++++++++---- src/Encryption.cs | 2 +- src/TL.cs | 19 +++++++++++++------ 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/Client.cs b/src/Client.cs index c8b6791..144ef92 100644 --- a/src/Client.cs +++ b/src/Client.cs @@ -307,7 +307,7 @@ namespace WTelegram throw new ApplicationException($"Received a packet encrypted with unexpected key {authKeyId:X}"); if (authKeyId == 0) // Unencrypted message { - using var reader = new BinaryReader(new MemoryStream(data, 8, data.Length - 8)); + using var reader = new TL.BinaryReader(new MemoryStream(data, 8, data.Length - 8), this); long msgId = _lastRecvMsgId = reader.ReadInt64(); if ((msgId & 1) == 0) throw new ApplicationException($"Invalid server msgId {msgId}"); int length = reader.ReadInt32(); @@ -327,7 +327,7 @@ namespace WTelegram byte[] decrypted_data = EncryptDecryptMessage(data.AsSpan(24), false, _session.AuthKey, msgKeyLarge); if (decrypted_data.Length < 36) // header below+ctorNb throw new ApplicationException($"Decrypted packet too small: {decrypted_data.Length}"); - using var reader = new BinaryReader(new MemoryStream(decrypted_data)); + using var reader = new TL.BinaryReader(new MemoryStream(decrypted_data), this); var serverSalt = reader.ReadInt64(); // int64 salt var sessionId = reader.ReadInt64(); // int64 session_id var msgId = _lastRecvMsgId = reader.ReadInt64();// int64 message_id @@ -385,7 +385,7 @@ namespace WTelegram }; } - internal MsgContainer ReadMsgContainer(BinaryReader reader) + internal MsgContainer ReadMsgContainer(TL.BinaryReader reader) { int count = reader.ReadInt32(); var array = new _Message[count]; @@ -422,7 +422,7 @@ namespace WTelegram return new MsgContainer { messages = array }; } - private RpcResult ReadRpcResult(BinaryReader reader) + private RpcResult ReadRpcResult(TL.BinaryReader reader) { long msgId = reader.ReadInt64(); var (type, tcs) = PullPendingRequest(msgId); @@ -838,5 +838,34 @@ namespace WTelegram reply_to_msg_id: reply_to_msg_id, entities: entities, schedule_date: schedule_date); } #endregion + + /// Enable the collection of id/access_hash pairs (experimental) + public bool CollectAccessHash { get; set; } + readonly Dictionary> _accessHashes = new(); + public IEnumerable> AllAccessHashesFor() where T : ITLObject + => _accessHashes.GetValueOrDefault(typeof(T)); + /// Retrieve the access_hash associated with this id (for a TL class) + /// a TL object class. For example User, Channel or Photo + public long? GetAccessHashFor(long id) where T : ITLObject + { + lock (_accessHashes) + return _accessHashes.GetOrCreate(typeof(T)).TryGetValue(id, out var access_hash) ? access_hash : null; + } + public void SetAccessHashFor(long id, long access_hash) where T : ITLObject + { + lock (_accessHashes) + _accessHashes.GetOrCreate(typeof(T))[id] = access_hash; + } + internal void UpdateAccessHash(object obj, Type type, object access_hash) + { + if (!CollectAccessHash) return; + if (access_hash is not long accessHash) return; + if (type.GetField("id") is not FieldInfo idField) return; + if (idField.GetValue(obj) is not long id) + if (idField.GetValue(obj) is not int idInt) return; + else id = idInt; + lock (_accessHashes) + _accessHashes.GetOrCreate(type)[id] = accessHash; + } } } diff --git a/src/Encryption.cs b/src/Encryption.cs index 581e6d3..1fae77c 100644 --- a/src/Encryption.cs +++ b/src/Encryption.cs @@ -109,7 +109,7 @@ namespace WTelegram var (tmp_aes_key, tmp_aes_iv) = ConstructTmpAESKeyIV(resPQ.server_nonce, pqInnerData.new_nonce); var answer = AES_IGE_EncryptDecrypt(serverDHparamsOk.encrypted_answer, tmp_aes_key, tmp_aes_iv, false); - using var encryptedReader = new BinaryReader(new MemoryStream(answer)); + using var encryptedReader = new TL.BinaryReader(new MemoryStream(answer), client); var answerHash = encryptedReader.ReadBytes(20); var answerObj = encryptedReader.ReadTLObject(); if (answerObj is not ServerDHInnerData serverDHinnerData) throw new ApplicationException("not server_DH_inner_data"); diff --git a/src/TL.cs b/src/TL.cs index db532f0..4a3e698 100644 --- a/src/TL.cs +++ b/src/TL.cs @@ -24,7 +24,7 @@ namespace TL internal static T Deserialize(byte[] bytes) where T : ITLObject { using var memStream = new MemoryStream(bytes); - using var reader = new BinaryReader(memStream); + using var reader = new BinaryReader(memStream, null); return (T)reader.ReadTLObject(); } @@ -56,7 +56,7 @@ namespace TL if (!Table.TryGetValue(ctorNb, out var type)) throw new ApplicationException($"Cannot find type for ctor #{ctorNb:x}"); var obj = Activator.CreateInstance(type); - var fields = obj.GetType().GetFields().GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g); + var fields = type.GetFields().GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g); int flags = 0; IfFlagAttribute ifFlag; foreach (var field in fields) @@ -64,9 +64,10 @@ namespace TL if (((ifFlag = field.GetCustomAttribute()) != null) && (flags & (1 << ifFlag.Bit)) == 0) continue; object value = reader.ReadTLValue(field.FieldType); field.SetValue(obj, value); - if (field.Name.Equals("Flags", StringComparison.OrdinalIgnoreCase)) flags = (int)value; + if (field.Name == "flags") flags = (int)value; + else if (field.Name == "access_hash") reader.Client?.UpdateAccessHash(obj, type, value); } - return type == typeof(GzipPacked) ? UnzipPacket((GzipPacked)obj) : (ITLObject)obj; + return type == typeof(GzipPacked) ? UnzipPacket((GzipPacked)obj, reader.Client) : (ITLObject)obj; } internal static void WriteTLValue(this BinaryWriter writer, object value) @@ -220,9 +221,9 @@ namespace TL writer.Write(0); // null arrays are serialized as empty } - internal static ITLObject UnzipPacket(GzipPacked obj) + internal static ITLObject UnzipPacket(GzipPacked obj, WTelegram.Client client) { - using var reader = new BinaryReader(new GZipStream(new MemoryStream(obj.packed_data), CompressionMode.Decompress)); + using var reader = new BinaryReader(new GZipStream(new MemoryStream(obj.packed_data), CompressionMode.Decompress), client); var result = reader.ReadTLObject(); return result; } @@ -234,6 +235,12 @@ namespace TL #endif } + public class BinaryReader : System.IO.BinaryReader + { + public readonly WTelegram.Client Client; + public BinaryReader(Stream stream, WTelegram.Client client) : base(stream) => Client = client; + } + [AttributeUsage(AttributeTargets.Class)] public class TLDefAttribute : Attribute {