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
{