From a038be87af41f9799a65bce870d55e7dd57d9ada Mon Sep 17 00:00:00 2001 From: Wizou <11647984+wiz0u@users.noreply.github.com> Date: Fri, 11 Nov 2022 00:33:29 +0100 Subject: [PATCH] Improved Secret Chats: Support layer 144 : big documents, silent (layer not yet supported by other clients) List of ISecretChat with detailed properties Fix PFS issue losing a message... --- .github/dev.yml | 2 +- .github/release.yml | 2 +- Examples/Program_SecretChats.cs | 31 +-- FAQ.md | 2 +- src/Encryption.cs | 2 +- src/SecretChats.cs | 93 ++++---- src/TL.Schema.cs | 2 +- src/TL.Secret.cs | 411 ++++++++++++++++++-------------- src/TL.Table.cs | 56 ++--- 9 files changed, 326 insertions(+), 275 deletions(-) diff --git a/.github/dev.yml b/.github/dev.yml index ddfdabc..02d8f36 100644 --- a/.github/dev.yml +++ b/.github/dev.yml @@ -2,7 +2,7 @@ pr: none trigger: - master -name: 3.0.4-dev.$(Rev:r) +name: 3.1.1-dev.$(Rev:r) pool: vmImage: ubuntu-latest diff --git a/.github/release.yml b/.github/release.yml index 9a0e1a8..250e994 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -1,7 +1,7 @@ pr: none trigger: none -name: 3.0.$(Rev:r) +name: 3.1.$(Rev:r) pool: vmImage: ubuntu-latest diff --git a/Examples/Program_SecretChats.cs b/Examples/Program_SecretChats.cs index c204af8..4b0edf0 100644 --- a/Examples/Program_SecretChats.cs +++ b/Examples/Program_SecretChats.cs @@ -4,23 +4,24 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using TL; +using WTelegram; namespace WTelegramClientTest { static class Program_SecretChats { - static WTelegram.Client Client; - static WTelegram.SecretChats Secrets; - static InputEncryptedChat ActiveChat; // the secret chat currently selected + static Client Client; + static SecretChats Secrets; + static ISecretChat ActiveChat; // the secret chat currently selected static readonly Dictionary Users = new(); static readonly Dictionary Chats = new(); // go to Project Properties > Debug > Environment variables and add at least these: api_id, api_hash, phone_number static async Task Main() { - WTelegram.Helpers.Log = (l, s) => System.Diagnostics.Debug.WriteLine(s); - Client = new WTelegram.Client(Environment.GetEnvironmentVariable); - Secrets = new WTelegram.SecretChats(Client, "Secrets.bin"); + Helpers.Log = (l, s) => System.Diagnostics.Debug.WriteLine(s); + Client = new Client(Environment.GetEnvironmentVariable); + Secrets = new SecretChats(Client, "Secrets.bin"); AppDomain.CurrentDomain.ProcessExit += (s, e) => { Secrets.Dispose(); Client.Dispose(); }; SelectActiveChat(); @@ -46,9 +47,9 @@ Type a command, or a message to send to the active secret chat:"); var line = Console.ReadLine(); if (line.StartsWith('/')) { - if (line == "/discard delete") { await Secrets.Discard(ActiveChat, true); SelectActiveChat(); } - else if (line == "/discard") { await Secrets.Discard(ActiveChat, false); SelectActiveChat(); } - else if (line == "/read") await Client.Messages_ReadEncryptedHistory(ActiveChat, DateTime.UtcNow); + if (line == "/discard delete") { await Secrets.Discard(ActiveChat.ChatId, true); SelectActiveChat(); } + else if (line == "/discard") { await Secrets.Discard(ActiveChat.ChatId, false); SelectActiveChat(); } + else if (line == "/read") await Client.Messages_ReadEncryptedHistory(ActiveChat.Peer, DateTime.UtcNow); else if (line == "/users") foreach (var user in Users.Values) Console.WriteLine($"{user.id,-10} {user}"); else if (line.StartsWith("/select ")) SelectActiveChat(int.Parse(line[8..])); else if (line.StartsWith("/request ")) @@ -58,15 +59,15 @@ Type a command, or a message to send to the active secret chat:"); Console.WriteLine("User not found"); else if (line.StartsWith("/photo ")) { - var media = new TL.Layer45.DecryptedMessageMediaPhoto { caption = line[7..] }; + var media = new TL.Layer46.DecryptedMessageMediaPhoto { caption = line[7..] }; var file = await Secrets.UploadFile(File.OpenRead(line[7..]), media); - var sent = await Secrets.SendMessage(ActiveChat, new TL.Layer73.DecryptedMessage { random_id = WTelegram.Helpers.RandomLong(), + var sent = await Secrets.SendMessage(ActiveChat.ChatId, new TL.Layer73.DecryptedMessage { random_id = Helpers.RandomLong(), media = media, flags = TL.Layer73.DecryptedMessage.Flags.has_media }, file: file); } else Console.WriteLine("Unrecognized command"); } else if (ActiveChat == null) Console.WriteLine("No active secret chat"); - else await Secrets.SendMessage(ActiveChat, new TL.Layer73.DecryptedMessage { message = line, random_id = WTelegram.Helpers.RandomLong() }); + else await Secrets.SendMessage(ActiveChat.ChatId, new TL.Layer73.DecryptedMessage { message = line, random_id = Helpers.RandomLong() }); } catch (Exception ex) { @@ -86,7 +87,7 @@ Type a command, or a message to send to the active secret chat:"); await Secrets.HandleUpdate(ue); break; case UpdateNewEncryptedMessage unem: // Encrypted message or service message: - if (unem.message.ChatId != ActiveChat?.chat_id) SelectActiveChat(unem.message.ChatId); + if (unem.message.ChatId != ActiveChat?.ChatId) SelectActiveChat(unem.message.ChatId); foreach (var msg in Secrets.DecryptMessage(unem.message)) { if (msg.Media != null && unem.message is EncryptedMessage { file: EncryptedFile ef }) @@ -110,8 +111,8 @@ Type a command, or a message to send to the active secret chat:"); private static void SelectActiveChat(int newActiveChat = 0) { - ActiveChat = Secrets.Peers.FirstOrDefault(sc => newActiveChat == 0 || sc.chat_id == newActiveChat); - Console.WriteLine("Active secret chat ID: " + ActiveChat?.chat_id); + ActiveChat = Secrets.Chats.FirstOrDefault(sc => newActiveChat == 0 || sc.ChatId == newActiveChat); + Console.WriteLine("Active secret chat ID: " + ActiveChat?.ChatId); } } } diff --git a/FAQ.md b/FAQ.md index 188d5dd..9a1c8d8 100644 --- a/FAQ.md +++ b/FAQ.md @@ -140,7 +140,7 @@ Some additional advices from me: 5. Avoid repetitive polling or repetitive sequence of actions/requests: Save the initial results of your queries, and update those results when you're informed of a change through `OnUpdate` events. 6. Don't buy fake user accounts/sessions and don't extract api_id/hash/authkey/sessions from official clients, this is [specifically forbidden by API TOS](https://core.telegram.org/api/terms#2-transparency). You must use your own api_id and create your own sessions associated with it. -7. If a phone number is brand new, it will be closely monitored by Telegram for abuse, and it can even already be considered a bad user due to bad behavior from the previous owner of that phone number (which may happens often with VoIP or other easy-to-buy-online numbers, so expect fast ban) +7. If a phone number is brand new, it will be closely monitored by Telegram for abuse, and it can even already be considered a bad user due to bad behavior from the previous owner of that phone number (which may happen often with VoIP or other easy-to-buy-online numbers, so expect fast ban) 8. You may want to use your new phone number account with an official Telegram client and act like a normal user for some time (some weeks/months), before using it for automation with WTelegramClient. 9. When creating a new API ID/Hash, I recommend you use your own phone number with long history of normal Telegram usage, rather than a brand new phone number with short history. In particular, DON'T create an API ID/Hash for every phone numbers you will control. One API ID/Hash represents your application, which can be used to control several user accounts. diff --git a/src/Encryption.cs b/src/Encryption.cs index 450e35f..a3a3eaf 100644 --- a/src/Encryption.cs +++ b/src/Encryption.cs @@ -531,7 +531,7 @@ j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB private readonly ICryptoTransform aesCrypto; private readonly byte[] prevBytes; - public AES_IGE_Stream(Stream stream, int size, byte[] key, byte[] iv) : this(stream, key, iv, false) { ContentLength = size; } + public AES_IGE_Stream(Stream stream, long size, byte[] key, byte[] iv) : this(stream, key, iv, false) { ContentLength = size; } public AES_IGE_Stream(Stream stream, byte[] key, byte[] iv, bool encrypt) : base(stream) { aesCrypto = encrypt ? Encryption.AesECB.CreateEncryptor(key, null) : Encryption.AesECB.CreateDecryptor(key, null); diff --git a/src/SecretChats.cs b/src/SecretChats.cs index 8065b5f..b857422 100644 --- a/src/SecretChats.cs +++ b/src/SecretChats.cs @@ -13,6 +13,14 @@ using static WTelegram.Encryption; namespace WTelegram { + public interface ISecretChat + { + int ChatId { get; } + long RemoteUserId { get; } + InputEncryptedChat Peer { get; } + int RemoteLayer { get; } + } + public sealed class SecretChats : IDisposable { public event Action OnChanged; @@ -28,7 +36,7 @@ namespace WTelegram private const int ThresholdPFS = 100; [TLDef(0xFEFEFEFE)] - internal class SecretChat : IObject + internal class SecretChat : IObject, ISecretChat { [Flags] public enum Flags : uint { requestChat = 1, renewKey = 2, acceptKey = 4, originator = 8, commitKey = 16 } public Flags flags; @@ -43,8 +51,12 @@ namespace WTelegram public long exchange_id; public int ChatId => peer.chat_id; + public long RemoteUserId => participant_id; + public InputEncryptedChat Peer => peer; + public int RemoteLayer => remoteLayer; + internal long key_fingerprint; - internal SortedList pendingMsgs = new(); + internal SortedList pendingMsgs = new(); internal void Discarded() // clear out fields for more security { Array.Clear(authKey, 0, authKey.Length); @@ -67,13 +79,7 @@ namespace WTelegram } public void Dispose() { OnChanged?.Invoke(); storage?.Dispose(); sha256.Dispose(); sha1.Dispose(); } - public List Peers => chats.Values.Select(sc => sc.peer).ToList(); - - /// Return secret chats with the given remote user ID - /// remote user ID - /// List of matching secret chat ids/access_hash - public List FindChatsByParticipant(long participant_id) - => chats.Where(kvp => kvp.Value.participant_id == participant_id).Select(kvp => kvp.Value.peer).ToList(); + public List Chats => chats.Values.ToList(); public bool IsChatActive(int chat_id) => !(chats.GetValueOrDefault(chat_id)?.flags.HasFlag(SecretChat.Flags.requestChat) ?? true); @@ -253,16 +259,16 @@ namespace WTelegram private async Task SendNotifyLayer(SecretChat chat) { - await SendMessage(chat.ChatId, new TL.Layer17.DecryptedMessageService { random_id = Helpers.RandomLong(), - action = new TL.Layer17.DecryptedMessageActionNotifyLayer { layer = Layer.SecretChats } }); + await SendMessage(chat.ChatId, new TL.Layer23.DecryptedMessageService { random_id = Helpers.RandomLong(), + action = new TL.Layer23.DecryptedMessageActionNotifyLayer { layer = Layer.SecretChats } }); if (chat.remoteLayer < Layer.MTProto2) chat.remoteLayer = Layer.MTProto2; } /// Encrypt and send a message on a secret chat - /// You would typically pass an instance of or that you created and filled + /// You would typically pass an instance of or that you created and filled ///
Remember to fill random_id with , and the flags field if necessary
/// Secret Chat ID - /// The pre-filled DecryptedMessage or DecryptedMessageService to send + /// The pre-filled DecryptedMessage or DecryptedMessageService to send /// Send encrypted message without a notification /// Optional file attachment. See method UploadFile /// Confirmation of sent message @@ -271,7 +277,7 @@ namespace WTelegram if (!chats.TryGetValue(chatId, out var chat)) throw new ApplicationException("Secret chat not found"); try { - var dml = new TL.Layer17.DecryptedMessageLayer + var dml = new TL.Layer23.DecryptedMessageLayer { layer = Math.Min(chat.remoteLayer, Layer.SecretChats), random_bytes = new byte[15], @@ -290,7 +296,7 @@ namespace WTelegram } } - private async Task SendMessage(SecretChat chat, TL.Layer17.DecryptedMessageLayer dml, bool silent = false, InputEncryptedFileBase file = null) + private async Task SendMessage(SecretChat chat, TL.Layer23.DecryptedMessageLayer dml, bool silent = false, InputEncryptedFileBase file = null) { RNG.GetBytes(dml.random_bytes); int x = 8 - (int)(chat.flags & SecretChat.Flags.originator); @@ -321,7 +327,7 @@ namespace WTelegram CheckPFS(chat); if (file != null) return await client.Messages_SendEncryptedFile(chat.peer, dml.message.RandomId, data, file, silent); - else if (dml.message is TL.Layer17.DecryptedMessageService or TL.Layer8.DecryptedMessageService) + else if (dml.message is TL.Layer23.DecryptedMessageService or TL.Layer8.DecryptedMessageService) return await client.Messages_SendEncryptedService(chat.peer, dml.message.RandomId, data); else return await client.Messages_SendEncrypted(chat.peer, dml.message.RandomId, data, silent); @@ -360,7 +366,7 @@ namespace WTelegram /// Decrypt an encrypted message obtained in /// Encrypted /// If messages are missing or received in wrong order, automatically request to resend missing messages - /// An array of DecryptedMessage or DecryptedMessageService from various TL.LayerXX namespaces.
+ /// An array of DecryptedMessage or DecryptedMessageService from various TL.LayerXX namespaces.
/// You can use the generic properties to access their fields /// May return an empty array if msg was already previously received or is not the next message in sequence. ///
May return multiple messages if missing messages are finally received (using = true)
@@ -371,7 +377,7 @@ namespace WTelegram try { var obj = Decrypt(chat, msg.Bytes, msg.Bytes.Length); - if (obj is not TL.Layer17.DecryptedMessageLayer dml) throw new ApplicationException("Decrypted object is not DecryptedMessageLayer"); + if (obj is not TL.Layer23.DecryptedMessageLayer dml) throw new ApplicationException("Decrypted object is not DecryptedMessageLayer"); if (dml.random_bytes.Length < 15) throw new ApplicationException("Not enough random_bytes"); if (((dml.out_seq_no ^ dml.in_seq_no) & 1) != 1 || ((dml.out_seq_no ^ chat.in_seq_no) & 1) != 0) throw new ApplicationException("Invalid seq_no parities"); if (dml.layer > chat.remoteLayer) chat.remoteLayer = dml.layer; @@ -384,8 +390,8 @@ namespace WTelegram if (lastPending == 0) lastPending = chat.in_seq_no; chat.pendingMsgs[dml.out_seq_no] = dml; if (dml.out_seq_no > lastPending + 2) // send request to resend missing gap asynchronously - _ = SendMessage(chat.ChatId, new TL.Layer17.DecryptedMessageService { random_id = Helpers.RandomLong(), - action = new TL.Layer17.DecryptedMessageActionResend { start_seq_no = lastPending + 2, end_seq_no = dml.out_seq_no - 2 } }); + _ = SendMessage(chat.ChatId, new TL.Layer23.DecryptedMessageService { random_id = Helpers.RandomLong(), + action = new TL.Layer23.DecryptedMessageActionResend { start_seq_no = lastPending + 2, end_seq_no = dml.out_seq_no - 2 } }); return Array.Empty(); } chat.in_seq_no = dml.out_seq_no; @@ -423,13 +429,13 @@ namespace WTelegram { switch (action) { - case TL.Layer17.DecryptedMessageActionNotifyLayer dmanl: + case TL.Layer23.DecryptedMessageActionNotifyLayer dmanl: chat.remoteLayer = dmanl.layer; return true; - case TL.Layer17.DecryptedMessageActionResend resend: + case TL.Layer23.DecryptedMessageActionResend resend: Helpers.Log(1, $"SC{(short)chat.ChatId:X4}> Resend {resend.start_seq_no}-{resend.end_seq_no}"); - var msgSvc = new TL.Layer17.DecryptedMessageService { action = new TL.Layer20.DecryptedMessageActionNoop() }; - var dml = new TL.Layer17.DecryptedMessageLayer + var msgSvc = new TL.Layer23.DecryptedMessageService { action = new TL.Layer23.DecryptedMessageActionNoop() }; + var dml = new TL.Layer23.DecryptedMessageLayer { layer = Math.Min(chat.remoteLayer, Layer.SecretChats), random_bytes = new byte[15], @@ -442,13 +448,13 @@ namespace WTelegram _ = SendMessage(chat, dml); } return true; - case TL.Layer20.DecryptedMessageActionNoop: + case TL.Layer23.DecryptedMessageActionNoop: Helpers.Log(1, $"SC{(short)chat.ChatId:X4}> Noop"); return true; - case TL.Layer20.DecryptedMessageActionRequestKey: - case TL.Layer20.DecryptedMessageActionAcceptKey: - case TL.Layer20.DecryptedMessageActionCommitKey: - case TL.Layer20.DecryptedMessageActionAbortKey: + case TL.Layer23.DecryptedMessageActionRequestKey: + case TL.Layer23.DecryptedMessageActionAcceptKey: + case TL.Layer23.DecryptedMessageActionCommitKey: + case TL.Layer23.DecryptedMessageActionAbortKey: Helpers.Log(1, $"SC{(short)chat.ChatId:X4}> PFS {action.GetType().Name[22..]}"); HandlePFS(chat, action); return true; @@ -465,16 +471,17 @@ namespace WTelegram else { Helpers.Log(4, "SC{(short)chat.ChatId:X4}> PFS Failure"); _ = Discard(chat.ChatId); return; } try { + chat.flags |= SecretChat.Flags.renewKey; Helpers.Log(1, $"SC{(short)chat.ChatId:X4}> PFS RenewKey"); + await Task.Delay(100); chat.salt = new byte[256]; RNG.GetBytes(chat.salt); var a = BigEndianInteger(chat.salt); var g_a = BigInteger.ModPow(dh.g, a, dh_prime); CheckGoodGaAndGb(g_a, dh_prime); - chat.flags |= SecretChat.Flags.renewKey; chat.exchange_id = Helpers.RandomLong(); - await SendMessage(chat.ChatId, new TL.Layer17.DecryptedMessageService { random_id = Helpers.RandomLong(), - action = new TL.Layer20.DecryptedMessageActionRequestKey { exchange_id = chat.exchange_id, g_a = g_a.To256Bytes() } }); + await SendMessage(chat.ChatId, new TL.Layer23.DecryptedMessageService { random_id = Helpers.RandomLong(), + action = new TL.Layer23.DecryptedMessageActionRequestKey { exchange_id = chat.exchange_id, g_a = g_a.To256Bytes() } }); } catch (Exception ex) { @@ -489,7 +496,7 @@ namespace WTelegram { switch (action) { - case TL.Layer20.DecryptedMessageActionRequestKey request: + case TL.Layer23.DecryptedMessageActionRequestKey request: switch (chat.flags & (SecretChat.Flags.requestChat | SecretChat.Flags.renewKey | SecretChat.Flags.acceptKey)) { case SecretChat.Flags.renewKey: // Concurrent Re-Keying @@ -517,10 +524,10 @@ namespace WTelegram chat.salt = gab.To256Bytes(); chat.exchange_id = request.exchange_id; var key_fingerprint = BinaryPrimitives.ReadInt64LittleEndian(sha1.ComputeHash(chat.salt).AsSpan(12)); - await SendMessage(chat.ChatId, new TL.Layer17.DecryptedMessageService { random_id = Helpers.RandomLong(), - action = new TL.Layer20.DecryptedMessageActionAcceptKey { exchange_id = request.exchange_id, g_b = g_b.To256Bytes(), key_fingerprint = key_fingerprint } }); + await SendMessage(chat.ChatId, new TL.Layer23.DecryptedMessageService { random_id = Helpers.RandomLong(), + action = new TL.Layer23.DecryptedMessageActionAcceptKey { exchange_id = request.exchange_id, g_b = g_b.To256Bytes(), key_fingerprint = key_fingerprint } }); break; - case TL.Layer20.DecryptedMessageActionAcceptKey accept: + case TL.Layer23.DecryptedMessageActionAcceptKey accept: if ((chat.flags & (SecretChat.Flags.requestChat | SecretChat.Flags.renewKey | SecretChat.Flags.acceptKey)) != SecretChat.Flags.renewKey) throw new ApplicationException("Invalid AcceptKey"); if (accept.exchange_id != chat.exchange_id) @@ -533,13 +540,13 @@ namespace WTelegram key_fingerprint = BinaryPrimitives.ReadInt64LittleEndian(sha1.ComputeHash(authKey).AsSpan(12)); if (accept.key_fingerprint != key_fingerprint) throw new ApplicationException("AcceptKey: key_fingerprint mismatch"); - _ = SendMessage(chat.ChatId, new TL.Layer17.DecryptedMessageService { random_id = Helpers.RandomLong(), - action = new TL.Layer20.DecryptedMessageActionCommitKey { exchange_id = accept.exchange_id, key_fingerprint = accept.key_fingerprint } }); + _ = SendMessage(chat.ChatId, new TL.Layer23.DecryptedMessageService { random_id = Helpers.RandomLong(), + action = new TL.Layer23.DecryptedMessageActionCommitKey { exchange_id = accept.exchange_id, key_fingerprint = accept.key_fingerprint } }); chat.salt = chat.authKey; // A may only discard the previous key after a message encrypted with the new key has been received. SetAuthKey(chat, authKey); chat.flags = chat.flags & ~SecretChat.Flags.renewKey | SecretChat.Flags.commitKey; break; - case TL.Layer20.DecryptedMessageActionCommitKey commit: + case TL.Layer23.DecryptedMessageActionCommitKey commit: if ((chat.flags & (SecretChat.Flags.requestChat | SecretChat.Flags.renewKey | SecretChat.Flags.acceptKey)) != SecretChat.Flags.acceptKey) throw new ApplicationException("Invalid RequestKey"); key_fingerprint = BinaryPrimitives.ReadInt64LittleEndian(sha1.ComputeHash(chat.salt).AsSpan(12)); @@ -549,10 +556,10 @@ namespace WTelegram authKey = chat.authKey; SetAuthKey(chat, chat.salt); Array.Clear(authKey, 0, authKey.Length); // the old key must be securely discarded - await SendMessage(chat.ChatId, new TL.Layer17.DecryptedMessageService { random_id = Helpers.RandomLong(), - action = new TL.Layer20.DecryptedMessageActionNoop() }); + await SendMessage(chat.ChatId, new TL.Layer23.DecryptedMessageService { random_id = Helpers.RandomLong(), + action = new TL.Layer23.DecryptedMessageActionNoop() }); break; - case TL.Layer20.DecryptedMessageActionAbortKey abort: + case TL.Layer23.DecryptedMessageActionAbortKey abort: if ((chat.flags & (SecretChat.Flags.renewKey | SecretChat.Flags.acceptKey)) == 0 || chat.flags.HasFlag(SecretChat.Flags.commitKey) || abort.exchange_id != chat.exchange_id) return; @@ -579,7 +586,7 @@ namespace WTelegram byte[] aes_key = new byte[32], aes_iv = new byte[32]; RNG.GetBytes(aes_key); RNG.GetBytes(aes_iv); - media.SizeKeyIV = (checked((int)stream.Length), aes_key, aes_iv); + media.SizeKeyIV = (stream.Length, aes_key, aes_iv); using var md5 = MD5.Create(); md5.TransformBlock(aes_key, 0, 32, null, 0); diff --git a/src/TL.Schema.cs b/src/TL.Schema.cs index eb74e8c..a9026f8 100644 --- a/src/TL.Schema.cs +++ b/src/TL.Schema.cs @@ -13179,7 +13179,7 @@ namespace TL public DocumentBase static_icon; /// The animated sticker to show when the user opens the reaction dropdown public DocumentBase appear_animation; - /// The animated sticker to show when the user selects this reaction + /// The animated sticker to show when the user hovers over the reaction public DocumentBase select_animation; /// The animated sticker to show when the reaction is chosen and activated public DocumentBase activate_animation; diff --git a/src/TL.Secret.cs b/src/TL.Secret.cs index 1cf43a6..1253e9b 100644 --- a/src/TL.Secret.cs +++ b/src/TL.Secret.cs @@ -32,7 +32,7 @@ namespace TL public abstract class DecryptedMessageMedia : IObject { public virtual string MimeType { get; } - internal virtual (int size, byte[] key, byte[] iv) SizeKeyIV { get => default; set => throw new ApplicationException("Incompatible DecryptedMessageMedia"); } + internal virtual (long size, byte[] key, byte[] iv) SizeKeyIV { get => default; set => throw new ApplicationException("Incompatible DecryptedMessageMedia"); } } /// Object describes the action to which a service message is linked. See @@ -110,7 +110,7 @@ namespace TL public byte[] iv; public override string MimeType => "image/jpeg"; - internal override (int, byte[], byte[]) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = value; } + internal override (long size, byte[] key, byte[] iv) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = (checked((int)value.size), value.key, value.iv); } } /// Video attached to an encrypted message. See [TLDef(0x4CEE6EF3)] @@ -135,7 +135,7 @@ namespace TL /// Initialization vector public byte[] iv; - internal override (int, byte[], byte[]) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = value; } + internal override (long size, byte[] key, byte[] iv) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = (checked((int)value.size), value.key, value.iv); } } /// GeoPoint attached to an encrypted message. See [TLDef(0x35480A59)] @@ -182,7 +182,7 @@ namespace TL /// File MIME-type public override string MimeType => mime_type; - internal override (int, byte[], byte[]) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = value; } + internal override (long size, byte[] key, byte[] iv) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = (checked((int)value.size), value.key, value.iv); } } /// Audio file attached to a secret chat message. See [TLDef(0x6080758F)] @@ -197,7 +197,7 @@ namespace TL /// Initialization vector public byte[] iv; - internal override (int, byte[], byte[]) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = value; } + internal override (long size, byte[] key, byte[] iv) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = (checked((int)value.size), value.key, value.iv); } } /// Setting of a message lifetime after reading. See @@ -233,8 +233,43 @@ namespace TL public class DecryptedMessageActionFlushHistory : DecryptedMessageAction { } } - namespace Layer17 + namespace Layer23 { + /// Image description. See + [TLDef(0x77BFB61B)] + public partial class PhotoSize : PhotoSizeBase + { + /// Thumbnail type » + public string type; + public FileLocationBase location; + /// Image width + public int w; + /// Image height + public int h; + /// File size + public int size; + + /// Thumbnail type » + public override string Type => type; + } + /// Description of an image and its content. See + [TLDef(0xE9A734FA)] + public partial class PhotoCachedSize : PhotoSizeBase + { + /// Thumbnail type + public string type; + public FileLocationBase location; + /// Image width + public int w; + /// Image height + public int h; + /// Binary data, file content + public byte[] bytes; + + /// Thumbnail type + public override string Type => type; + } + /// User is uploading a video. See [TLDef(0x92042FF7)] public class SendMessageUploadVideoAction : SendMessageAction { } @@ -248,6 +283,28 @@ namespace TL [TLDef(0x8FAEE98E)] public class SendMessageUploadDocumentAction : SendMessageAction { } + /// Defines a sticker See + [TLDef(0xFB0A5727)] + public class DocumentAttributeSticker : DocumentAttribute { } + /// Defines a video See + [TLDef(0x5910CCCB)] + public class DocumentAttributeVideo : DocumentAttribute + { + /// Duration in seconds + public int duration; + /// Video width + public int w; + /// Video height + public int h; + } + /// Represents an audio file See + [TLDef(0x051448E5)] + public class DocumentAttributeAudio : DocumentAttribute + { + /// Duration in seconds + public int duration; + } + /// Contents of an encrypted message. See [TLDef(0x204D3878)] public class DecryptedMessage : DecryptedMessageBase @@ -313,7 +370,7 @@ namespace TL /// MIME-type of the video file
Parameter added in Layer 17.
public override string MimeType => mime_type; - internal override (int, byte[], byte[]) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = value; } + internal override (long size, byte[] key, byte[] iv) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = (checked((int)value.size), value.key, value.iv); } } ///
Audio file attached to a secret chat message. See [TLDef(0x57E0A9CB)] @@ -333,7 +390,31 @@ namespace TL /// MIME-type of the audio file
Parameter added in Layer 13.
public override string MimeType => mime_type; - internal override (int, byte[], byte[]) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = value; } + internal override (long size, byte[] key, byte[] iv) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = (checked((int)value.size), value.key, value.iv); } + } + ///
Non-e2e documented forwarded from non-secret chat See + [TLDef(0xFA95B0DD)] + public class DecryptedMessageMediaExternalDocument : DecryptedMessageMedia + { + /// Document ID + public long id; + /// access hash + public long access_hash; + /// Date + public DateTime date; + /// Mime type + public string mime_type; + /// Size + public int size; + /// Thumbnail + public PhotoSizeBase thumb; + /// DC ID + public int dc_id; + /// Attributes for media types + public DocumentAttribute[] attributes; + + /// Mime type + public override string MimeType => mime_type; } /// Request for the other party in a Secret Chat to automatically resend a contiguous range of previously sent messages, as explained in Sequence number is Secret Chats. See @@ -359,6 +440,45 @@ namespace TL /// Type of action public SendMessageAction action; } + /// Request rekeying, see rekeying process See + [TLDef(0xF3C9611B)] + public class DecryptedMessageActionRequestKey : DecryptedMessageAction + { + /// Exchange ID + public long exchange_id; + /// g_a, see rekeying process + public byte[] g_a; + } + /// Accept new key See + [TLDef(0x6FE1735B)] + public class DecryptedMessageActionAcceptKey : DecryptedMessageAction + { + /// Exchange ID + public long exchange_id; + /// B parameter, see rekeying process + public byte[] g_b; + /// Key fingerprint, see rekeying process + public long key_fingerprint; + } + /// Abort rekeying See + [TLDef(0xDD05EC6B)] + public class DecryptedMessageActionAbortKey : DecryptedMessageAction + { + /// Exchange ID + public long exchange_id; + } + /// Commit new key, see rekeying process See + [TLDef(0xEC2E0B9B)] + public class DecryptedMessageActionCommitKey : DecryptedMessageAction + { + /// Exchange ID, see rekeying process + public long exchange_id; + /// Key fingerprint, see rekeying process + public long key_fingerprint; + } + /// NOOP action See + [TLDef(0xA82FDD63)] + public class DecryptedMessageActionNoop : DecryptedMessageAction { } /// Sets the layer number for the contents of an encrypted message. See [TLDef(0x1BE31789)] @@ -375,19 +495,49 @@ namespace TL /// The content of message itself public DecryptedMessageBase message; } + + /// File is currently unavailable. See + [TLDef(0x7C596B46)] + public class FileLocationUnavailable : FileLocationBase + { + /// Server volume + public long volume_id; + /// File ID + public int local_id; + /// Checksum to access the file + public long secret; + + /// Server volume + public override long VolumeId => volume_id; + /// File ID + public override int LocalId => local_id; + /// Checksum to access the file + public override long Secret => secret; + } + /// File location. See + [TLDef(0x53D69076)] + public class FileLocation : FileLocationBase + { + /// Number of the data center holding the file + public int dc_id; + /// Server volume + public long volume_id; + /// File ID + public int local_id; + /// Checksum to access the file + public long secret; + + /// Server volume + public override long VolumeId => volume_id; + /// File ID + public override int LocalId => local_id; + /// Checksum to access the file + public override long Secret => secret; + } } namespace Layer45 { - /// Defines a sticker See - [TLDef(0x3A556302)] - public class DocumentAttributeSticker : DocumentAttribute - { - /// Alternative emoji representation of sticker - public string alt; - /// Associated stickerset - public InputStickerSet stickerset; - } /// Represents an audio file See [TLDef(0xDED218E0)] public class DocumentAttributeAudio : DocumentAttribute @@ -399,6 +549,27 @@ namespace TL /// Performer public string performer; } + } + + namespace Layer46 + { + /// Defines a sticker See + [TLDef(0x3A556302)] + public class DocumentAttributeSticker : DocumentAttribute + { + /// Alternative emoji representation of sticker + public string alt; + /// Associated stickerset + public InputStickerSet stickerset; + } + + /// Message entity representing a user mention: for creating a mention use . See + [TLDef(0x352DCA58, inheritBefore = true)] + public class MessageEntityMentionName : MessageEntityMention + { + /// Identifier of the user that was mentioned + public int user_id; + } /// Contents of an encrypted message. See [TLDef(0x36B091DE)] @@ -475,7 +646,7 @@ namespace TL public string caption; public override string MimeType => "image/jpeg"; - internal override (int, byte[], byte[]) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = value; } + internal override (long size, byte[] key, byte[] iv) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = (checked((int)value.size), value.key, value.iv); } } /// Video attached to an encrypted message. See [TLDef(0x970C8C0E)] @@ -507,7 +678,7 @@ namespace TL /// MIME-type of the video file
Parameter added in Layer 17.
public override string MimeType => mime_type; - internal override (int, byte[], byte[]) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = value; } + internal override (long size, byte[] key, byte[] iv) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = (checked((int)value.size), value.key, value.iv); } } ///
Document attached to a message in a secret chat. See [TLDef(0x7AFE8AE2)] @@ -535,7 +706,7 @@ namespace TL /// File MIME-type public override string MimeType => mime_type; - internal override (int, byte[], byte[]) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = value; } + internal override (long size, byte[] key, byte[] iv) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = (checked((int)value.size), value.key, value.iv); } } /// Venue See [TLDef(0x8A0DF56F)] @@ -563,6 +734,13 @@ namespace TL } } + namespace Layer66 + { + /// User is uploading a round video See + [TLDef(0xBB718624)] + public class SendMessageUploadRoundAction : SendMessageAction { } + } + namespace Layer73 { /// Contents of an encrypted message. See @@ -592,6 +770,8 @@ namespace TL { /// Field has a value has_reply_to_random_id = 0x8, + /// Whether this is a silent message (no notification triggered) + silent = 0x20, /// Field has a value has_entities = 0x80, /// Field has a value @@ -623,180 +803,41 @@ namespace TL } } - namespace Layer20 + namespace Layer101 + { } + + namespace Layer143 { - /// Request rekeying, see rekeying process See - [TLDef(0xF3C9611B)] - public class DecryptedMessageActionRequestKey : DecryptedMessageAction + /// Document attached to a message in a secret chat. See + [TLDef(0x6ABD9782)] + public class DecryptedMessageMediaDocument : DecryptedMessageMedia { - /// Exchange ID - public long exchange_id; - /// g_a, see rekeying process - public byte[] g_a; - } - /// Accept new key See - [TLDef(0x6FE1735B)] - public class DecryptedMessageActionAcceptKey : DecryptedMessageAction - { - /// Exchange ID - public long exchange_id; - /// B parameter, see rekeying process - public byte[] g_b; - /// Key fingerprint, see rekeying process - public long key_fingerprint; - } - /// Abort rekeying See - [TLDef(0xDD05EC6B)] - public class DecryptedMessageActionAbortKey : DecryptedMessageAction - { - /// Exchange ID - public long exchange_id; - } - /// Commit new key, see rekeying process See - [TLDef(0xEC2E0B9B)] - public class DecryptedMessageActionCommitKey : DecryptedMessageAction - { - /// Exchange ID, see rekeying process - public long exchange_id; - /// Key fingerprint, see rekeying process - public long key_fingerprint; - } - /// NOOP action See - [TLDef(0xA82FDD63)] - public class DecryptedMessageActionNoop : DecryptedMessageAction { } - } - - namespace Layer23 - { - /// Image description. See - [TLDef(0x77BFB61B)] - public partial class PhotoSize : PhotoSizeBase - { - /// Thumbnail type » - public string type; - public FileLocationBase location; - /// Image width - public int w; - /// Image height - public int h; - /// File size - public int size; - - /// Thumbnail type » - public override string Type => type; - } - /// Description of an image and its content. See - [TLDef(0xE9A734FA)] - public partial class PhotoCachedSize : PhotoSizeBase - { - /// Thumbnail type - public string type; - public FileLocationBase location; - /// Image width - public int w; - /// Image height - public int h; - /// Binary data, file content - public byte[] bytes; - - /// Thumbnail type - public override string Type => type; - } - - /// Defines a sticker See - [TLDef(0xFB0A5727)] - public class DocumentAttributeSticker : DocumentAttribute { } - /// Defines a video See - [TLDef(0x5910CCCB)] - public class DocumentAttributeVideo : DocumentAttribute - { - /// Duration in seconds - public int duration; - /// Video width - public int w; - /// Video height - public int h; - } - /// Represents an audio file See - [TLDef(0x051448E5)] - public class DocumentAttributeAudio : DocumentAttribute - { - /// Duration in seconds - public int duration; - } - - /// Non-e2e documented forwarded from non-secret chat See - [TLDef(0xFA95B0DD)] - public class DecryptedMessageMediaExternalDocument : DecryptedMessageMedia - { - /// Document ID - public long id; - /// access hash - public long access_hash; - /// Date - public DateTime date; - /// Mime type + /// Thumbnail-file contents (JPEG-file, quality 55, set in a 90x90 square) + public byte[] thumb; + /// Thumbnail width + public int thumb_w; + /// Thumbnail height + public int thumb_h; + /// File MIME-type public string mime_type; - /// Size - public int size; - /// Thumbnail - public PhotoSizeBase thumb; - /// DC ID - public int dc_id; - /// Attributes for media types + /// Document size ( on layer <143, on layer >=143) + public long size; + /// Key to decrypt the attached document file + public byte[] key; + /// Initialization + public byte[] iv; + /// Document attributes for media types public DocumentAttribute[] attributes; + /// Caption + public string caption; - /// Mime type + /// File MIME-type public override string MimeType => mime_type; - } - /// File is currently unavailable. See - [TLDef(0x7C596B46)] - public class FileLocationUnavailable : FileLocationBase - { - /// Server volume - public long volume_id; - /// File ID - public int local_id; - /// Checksum to access the file - public long secret; - - /// Server volume - public override long VolumeId => volume_id; - /// File ID - public override int LocalId => local_id; - /// Checksum to access the file - public override long Secret => secret; - } - /// File location. See - [TLDef(0x53D69076)] - public class FileLocation : FileLocationBase - { - /// Number of the data center holding the file - public int dc_id; - /// Server volume - public long volume_id; - /// File ID - public int local_id; - /// Checksum to access the file - public long secret; - - /// Server volume - public override long VolumeId => volume_id; - /// File ID - public override int LocalId => local_id; - /// Checksum to access the file - public override long Secret => secret; + internal override (long size, byte[] key, byte[] iv) SizeKeyIV { get => (size, key, iv); set => (size, key, iv) = value; } } } - namespace Layer66 - { - /// User is uploading a round video See - [TLDef(0xBB718624)] - public class SendMessageUploadRoundAction : SendMessageAction { } - } - - namespace Layer46 + namespace Layer144 { } } diff --git a/src/TL.Table.cs b/src/TL.Table.cs index 77a69be..50a3c11 100644 --- a/src/TL.Table.cs +++ b/src/TL.Table.cs @@ -7,7 +7,7 @@ namespace TL public static class Layer { public const int Version = 148; // fetched 01/11/2022 17:33:23 - internal const int SecretChats = 101; + internal const int SecretChats = 144; internal const int MTProto2 = 73; internal const uint VectorCtor = 0x1CB5C415; internal const uint NullCtor = 0x56730BCC; @@ -1047,54 +1047,56 @@ namespace TL [0x71701DA9] = typeof(ForumTopic), [0x367617D3] = typeof(Messages_ForumTopics), // from TL.Secret: + [0x6ABD9782] = typeof(Layer143.DecryptedMessageMediaDocument), + [0x91CC4674] = typeof(Layer73.DecryptedMessage), [0xBB718624] = typeof(Layer66.SendMessageUploadRoundAction), - [0xE50511D8] = typeof(Layer45.DecryptedMessageMediaWebPage), - [0x8A0DF56F] = typeof(Layer45.DecryptedMessageMediaVenue), + [0xE50511D8] = typeof(Layer46.DecryptedMessageMediaWebPage), + [0x8A0DF56F] = typeof(Layer46.DecryptedMessageMediaVenue), + [0x352DCA58] = typeof(Layer46.MessageEntityMentionName), + [0x3A556302] = typeof(Layer46.DocumentAttributeSticker), + [0x7AFE8AE2] = typeof(Layer46.DecryptedMessageMediaDocument), + [0x970C8C0E] = typeof(Layer46.DecryptedMessageMediaVideo), + [0xF1FA8D78] = typeof(Layer46.DecryptedMessageMediaPhoto), + [0x36B091DE] = typeof(Layer46.DecryptedMessage), + [0xDED218E0] = typeof(Layer45.DocumentAttributeAudio), [0xFA95B0DD] = typeof(Layer23.DecryptedMessageMediaExternalDocument), [0x53D69076] = typeof(Layer23.FileLocation), [0x7C596B46] = typeof(Layer23.FileLocationUnavailable), [0xE9A734FA] = typeof(Layer23.PhotoCachedSize), [0x77BFB61B] = typeof(Layer23.PhotoSize), - [0xDED218E0] = typeof(Layer45.DocumentAttributeAudio), [0x051448E5] = typeof(Layer23.DocumentAttributeAudio), [0x5910CCCB] = typeof(Layer23.DocumentAttributeVideo), - [0x3A556302] = typeof(Layer45.DocumentAttributeSticker), [0xFB0A5727] = typeof(Layer23.DocumentAttributeSticker), - [0xA82FDD63] = typeof(Layer20.DecryptedMessageActionNoop), - [0xEC2E0B9B] = typeof(Layer20.DecryptedMessageActionCommitKey), - [0xDD05EC6B] = typeof(Layer20.DecryptedMessageActionAbortKey), - [0x6FE1735B] = typeof(Layer20.DecryptedMessageActionAcceptKey), - [0xF3C9611B] = typeof(Layer20.DecryptedMessageActionRequestKey), - [0xCCB27641] = typeof(Layer17.DecryptedMessageActionTyping), - [0xF3048883] = typeof(Layer17.DecryptedMessageActionNotifyLayer), - [0x511110B0] = typeof(Layer17.DecryptedMessageActionResend), - [0x8FAEE98E] = typeof(Layer17.SendMessageUploadDocumentAction), - [0x990A3C1A] = typeof(Layer17.SendMessageUploadPhotoAction), - [0xE6AC8A6F] = typeof(Layer17.SendMessageUploadAudioAction), - [0x92042FF7] = typeof(Layer17.SendMessageUploadVideoAction), - [0x1BE31789] = typeof(Layer17.DecryptedMessageLayer), + [0xA82FDD63] = typeof(Layer23.DecryptedMessageActionNoop), + [0xEC2E0B9B] = typeof(Layer23.DecryptedMessageActionCommitKey), + [0xDD05EC6B] = typeof(Layer23.DecryptedMessageActionAbortKey), + [0x6FE1735B] = typeof(Layer23.DecryptedMessageActionAcceptKey), + [0xF3C9611B] = typeof(Layer23.DecryptedMessageActionRequestKey), + [0xCCB27641] = typeof(Layer23.DecryptedMessageActionTyping), + [0xF3048883] = typeof(Layer23.DecryptedMessageActionNotifyLayer), + [0x511110B0] = typeof(Layer23.DecryptedMessageActionResend), + [0x8FAEE98E] = typeof(Layer23.SendMessageUploadDocumentAction), + [0x990A3C1A] = typeof(Layer23.SendMessageUploadPhotoAction), + [0xE6AC8A6F] = typeof(Layer23.SendMessageUploadAudioAction), + [0x92042FF7] = typeof(Layer23.SendMessageUploadVideoAction), + [0x1BE31789] = typeof(Layer23.DecryptedMessageLayer), + [0x57E0A9CB] = typeof(Layer23.DecryptedMessageMediaAudio), + [0x524A415D] = typeof(Layer23.DecryptedMessageMediaVideo), + [0x73164160] = typeof(Layer23.DecryptedMessageService), + [0x204D3878] = typeof(Layer23.DecryptedMessage), [0x6719E45C] = typeof(Layer8.DecryptedMessageActionFlushHistory), [0x8AC1F475] = typeof(Layer8.DecryptedMessageActionScreenshotMessages), [0x65614304] = typeof(Layer8.DecryptedMessageActionDeleteMessages), [0x0C4F40BE] = typeof(Layer8.DecryptedMessageActionReadMessages), - [0x57E0A9CB] = typeof(Layer17.DecryptedMessageMediaAudio), [0x6080758F] = typeof(Layer8.DecryptedMessageMediaAudio), - [0x7AFE8AE2] = typeof(Layer45.DecryptedMessageMediaDocument), [0xB095434B] = typeof(Layer8.DecryptedMessageMediaDocument), [0xA1733AEC] = typeof(Layer8.DecryptedMessageActionSetMessageTTL), [0x588A0A97] = typeof(Layer8.DecryptedMessageMediaContact), [0x35480A59] = typeof(Layer8.DecryptedMessageMediaGeoPoint), - [0x970C8C0E] = typeof(Layer45.DecryptedMessageMediaVideo), - [0x524A415D] = typeof(Layer17.DecryptedMessageMediaVideo), [0x4CEE6EF3] = typeof(Layer8.DecryptedMessageMediaVideo), - [0xF1FA8D78] = typeof(Layer45.DecryptedMessageMediaPhoto), [0x32798A8C] = typeof(Layer8.DecryptedMessageMediaPhoto), [0x089F5C4A] = null,//Layer8.DecryptedMessageMediaEmpty - [0x73164160] = typeof(Layer17.DecryptedMessageService), [0xAA48327D] = typeof(Layer8.DecryptedMessageService), - [0x91CC4674] = typeof(Layer73.DecryptedMessage), - [0x36B091DE] = typeof(Layer45.DecryptedMessage), - [0x204D3878] = typeof(Layer17.DecryptedMessage), [0x1F814F1F] = typeof(Layer8.DecryptedMessage), };