diff --git a/Apps/ClientConsoleApp/App.config b/Apps/ClientConsoleApp/App.config new file mode 100644 index 0000000..bc5b438 --- /dev/null +++ b/Apps/ClientConsoleApp/App.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Apps/ClientConsoleApp/ClientConsoleApp.csproj b/Apps/ClientConsoleApp/ClientConsoleApp.csproj new file mode 100644 index 0000000..95ed837 --- /dev/null +++ b/Apps/ClientConsoleApp/ClientConsoleApp.csproj @@ -0,0 +1,63 @@ + + + + + Debug + AnyCPU + {15296FBD-23B9-4786-8CC0-65C872FBFDAC} + Exe + ClientConsoleApp + ClientConsoleApp + v4.6 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + {d6144517-91d2-4880-86df-e9ff5d7f383a} + TeleSharp.TL + + + {400d2544-1cc6-4d8a-a62c-2292d9947a16} + TLSharp.Core + + + + \ No newline at end of file diff --git a/Apps/ClientConsoleApp/Program.cs b/Apps/ClientConsoleApp/Program.cs new file mode 100644 index 0000000..378f411 --- /dev/null +++ b/Apps/ClientConsoleApp/Program.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using TeleSharp.TL; +using TLSharp.Core; + +namespace ClientConsoleApp +{ + class Program + { + private static string NumberToSendMessage => ConfigurationManager.AppSettings[nameof(NumberToSendMessage)]; + + static void Main(string[] args) + { + Thread.Sleep(2000); + Console.WriteLine("Hello World!"); + + //var tcpClient = new TcpClient(); + //tcpClient.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000)); + //TestTcpClient(tcpClient); + //TestTcpClient(tcpClient); + + TelegramClient client = GetTlgClient().Result; + var normalizedNumber = NumberToSendMessage.StartsWith("+") ? + NumberToSendMessage.Substring(1, NumberToSendMessage.Length - 1) : + NumberToSendMessage; + + var result = client.GetContactsAsync().Result; + + var user = result.Users + .OfType() + .FirstOrDefault(x => x.Phone == normalizedNumber); + + var rr = client.SendTypingAsync(new TLInputPeerUser() { UserId = user.Id }).Result; + Thread.Sleep(3000); + var rrr = client.SendMessageAsync(new TLInputPeerUser() { UserId = user.Id }, "TEST").Result; + } + private static async Task GetTlgClient() + { + string ApiHash = ConfigurationManager.AppSettings["ApiHash"]; + int ApiId = int.Parse(ConfigurationManager.AppSettings["ApiId"]); + //string AuthCode = ConfigurationManager.AppSettings["AuthCode"]; + string MainPhoneNumber = ConfigurationManager.AppSettings["NumberToAuthenticate"]; + var client = new TelegramClient(ApiId, ApiHash, null, "session", null, "127.0.0.1", 5000);// + var phoneCodeHash = string.Empty; + authenticated: + Console.WriteLine("Start app"); + client.ConnectAsync().Wait(); + Console.WriteLine("MakeAuthentication"); + await MakeAuthentication(client, MainPhoneNumber); + + Console.WriteLine("Connected"); + if (!client.IsUserAuthorized()) + { + Console.WriteLine("User not autorized"); + if (string.IsNullOrEmpty(phoneCodeHash)) + { + phoneCodeHash = await client.SendCodeRequestAsync(MainPhoneNumber); + goto authenticated; + } + + Console.WriteLine("Plase enter new AuthCode:"); + var AuthCode = Console.ReadLine(); + var user = await client.MakeAuthAsync(MainPhoneNumber, phoneCodeHash, AuthCode); + Console.WriteLine("Login successfull."); + } + + return client; + } + + private static async Task MakeAuthentication(TLSharp.Core.TelegramClient client, string mainPhoneNumber) + { + var hash = await client.SendCodeRequestAsync(mainPhoneNumber); + Console.WriteLine("waiting for code"); + var code = Console.ReadLine(); + var user = await client.MakeAuthAsync(mainPhoneNumber, hash, code); + if (!client.IsUserAuthorized()) + { + hash = await client.SendCodeRequestAsync(mainPhoneNumber); + Console.WriteLine("please try again.add code"); + code = Console.ReadLine(); + user = await client.MakeAuthAsync(mainPhoneNumber, hash, code); + } + + } + + private static void TestTcpClient(TcpClient tcpClient) + { + if (tcpClient.Connected) + { + using (var memoryStream = new MemoryStream()) + { + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write((long)0); + binaryWriter.Write(1234); + binaryWriter.Write(20); + binaryWriter.Write(8000); + + byte[] packet = memoryStream.ToArray(); + + tcpClient.GetStream().WriteAsync(packet, 0, packet.Length).Wait(); + } + } + } + + Thread.Sleep(5000); + } + } +} diff --git a/Apps/ClientConsoleApp/Properties/AssemblyInfo.cs b/Apps/ClientConsoleApp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0f97770 --- /dev/null +++ b/Apps/ClientConsoleApp/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ClientConsoleApp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ClientConsoleApp")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("15296fbd-23b9-4786-8cc0-65c872fbfdac")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Apps/TlgListenerApplication/App.config b/Apps/TlgListenerApplication/App.config new file mode 100644 index 0000000..8324aa6 --- /dev/null +++ b/Apps/TlgListenerApplication/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Apps/TlgListenerApplication/Program.cs b/Apps/TlgListenerApplication/Program.cs new file mode 100644 index 0000000..c43629d --- /dev/null +++ b/Apps/TlgListenerApplication/Program.cs @@ -0,0 +1,442 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Threading.Tasks; +using Ionic.Crc; +using TLSharp.Core.Auth; +using TLSharp.Core.MTProto; +using TLSharp.Core.MTProto.Crypto; +using TLSharp.Core.Network; +using TLSharp.Core.Utils; + +namespace TlgListenerApplication +{ + class Program + { + private static int sequence = 0; + private static int timeOffset; + private static long lastMessageId; + private static Random random => new Random(); + + static void Main(string[] args) + { + Console.WriteLine("Listening..."); + TcpListener(); + Console.WriteLine("The end"); + Console.ReadKey(); + } + + private static void TcpListener() + { + try + { + var tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 5000); + tcpListener.Start(); + for (; ; ) + { + if (tcpListener.Pending()) + { + try + { + ProcessRequest(tcpListener); + } + catch (Exception e) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(e); + Console.ForegroundColor = ConsoleColor.Gray; + } + } + } + } + catch (Exception exception) + { + Console.WriteLine(exception); + } + } + + private static void ProcessRequest(TcpListener tcpListener) + { + Console.WriteLine("Processing..."); + var tcpClient = tcpListener.AcceptTcpClient(); + var netStream = tcpClient.GetStream(); + + //var getingCounter = 0; + //while (true) + //{ + // if (!netStream.DataAvailable) + // continue; + // Console.WriteLine("Get data " + ++getingCounter); + //} + + while (tcpClient.Connected) + { + System.Threading.Thread.Sleep(100); + if (!netStream.DataAvailable) continue; + + byte[] nonceFromClient = new byte[16]; + byte[] servernonce = new byte[16]; + byte[] newNonce = new byte[32]; + uint responseCode = 0; + const uint step1Constructor = 0x60469778; + const uint step2Constructor = 0xd712e4be; + const uint step3Constructor = 0xf5045f1f; + + if (netStream.CanRead) + { + var bytes = new byte[tcpClient.ReceiveBufferSize]; + netStream.Read(bytes, 0, (int)tcpClient.ReceiveBufferSize); + var tcpMessage = TcpMessage.Decode(bytes); + var binaryReader = new BinaryReader(new MemoryStream(tcpMessage.Body, false)); + + var authKeyId = binaryReader.ReadInt64(); + if (authKeyId == 0) + { + var msgId = binaryReader.ReadInt64(); + var datalength = binaryReader.ReadInt32(); + var data = binaryReader.ReadBytes(datalength); + + var binaryReader2 = new BinaryReader(new MemoryStream(data, false)); + + responseCode = binaryReader2.ReadUInt32(); + Console.WriteLine("Request code: " + responseCode); + if (responseCode == step1Constructor) //---Step1_PQRequest + { + nonceFromClient = binaryReader2.ReadBytes(16); + } + else if (responseCode == step2Constructor) //---Step1_PQRequest + { + nonceFromClient = binaryReader2.ReadBytes(16); + servernonce = binaryReader2.ReadBytes(16); + var useless = binaryReader2.ReadBytes(13); + var ciphertext = binaryReader2.ReadBytes(500); + var newnoncetemp = new byte[32]; + Array.Copy(ciphertext, ciphertext.Length - 32, newnoncetemp,0,32); + //ciphertext.CopyTo(newnoncetemp, ciphertext.Length - 32); + } + } + else + { + var decodeMessage = DecodeMessage(tcpMessage.Body); + var buffer = new byte[binaryReader.BaseStream.Length - 24]; + int count; + using (var ms = new MemoryStream()) + while ((count = binaryReader.Read(buffer, 0, buffer.Length)) != 0) + ms.Write(buffer, 0, count); + + //var keyData = Helpers.CalcKey(buffer, messageKey, false); + //var data = AES.DecryptAES(keyData, buffer); + } + + //var obj = new Step1_PQRequest().FromBytes(data); + //var rr = FromByteArray(data); + + //var binaryReader = new BinaryReader(netStream); + //var a = binaryReader.ReadInt64(); + //var b = binaryReader.ReadInt32(); + //var c = binaryReader.ReadInt32(); + //var d = binaryReader.ReadInt32(); + } + + if (netStream.CanWrite) + { + + var fingerprint = StringToByteArray("216be86c022bb4c3"); + + byte[] outputdata = null; + if (responseCode == step1Constructor) + { + var nonce = new byte[16]; + new Random().NextBytes(nonce); + outputdata = new Step1_Response() + { + Pq = new BigInteger(1, BitConverter.GetBytes(880)), + ServerNonce = nonceFromClient, + Nonce = nonce, + Fingerprints = new List() { fingerprint } + }.ToBytes(); + } + else if (responseCode == step2Constructor) + { + //var nonce = new byte[16]; + //new Random().NextBytes(nonce); + + byte[] answer; + var hashsum = Encoding.UTF8.GetBytes("asdfghjklmnbvcxzasdf"); + const uint innerCode = 0xb5890dba; + AESKeyData key = AES.GenerateKeyDataFromNonces(servernonce, newNonce); + using (var memoryStream = new MemoryStream()) + { + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(hashsum); + binaryWriter.Write(innerCode); + binaryWriter.Write(nonceFromClient); + binaryWriter.Write(newNonce); + binaryWriter.Write(123456789); + Serializers.Bytes.write(binaryWriter, new BigInteger(1, BitConverter.GetBytes(777)).ToByteArrayUnsigned()); + Serializers.Bytes.write(binaryWriter, new BigInteger(1, BitConverter.GetBytes(888)).ToByteArrayUnsigned()); + answer = memoryStream.ToArray(); + } + } + + outputdata = new Step2_Response() + { + ServerNonce = nonceFromClient, + Nonce = servernonce, + NewNonce = newNonce, + EncryptedAnswer = AES.EncryptAES(key, answer) + }.ToBytes(); + } + else if (responseCode == step3Constructor) + { + var newnonce = new byte[16]; + new Random().NextBytes(newnonce); + const uint innerCode = 0x3bcbf734; + using (var memoryStream = new MemoryStream()) + { + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(innerCode); + binaryWriter.Write(newnonce); + binaryWriter.Write(nonceFromClient); + binaryWriter.Write(newnonce); + outputdata = memoryStream.ToArray(); + } + } + } + + var bytes = PrepareToSend(outputdata); + var datatosend = Encode(bytes, 11); + netStream.Write(datatosend, 0, datatosend.Length); + } + else + { + Console.WriteLine("You cannot write data to this stream."); + tcpClient.Close(); + netStream.Close(); + } + } + } + + private static void ProcessRequestSocket(TcpListener tcpListener) + { + Console.WriteLine("Processing..."); + var tcpClient = tcpListener.AcceptSocket(); + + var bytes = new byte[tcpClient.ReceiveBufferSize]; + var countbyte = tcpClient.Receive(bytes); + + return; + + byte[] nonceFromClient = new byte[16]; + var tcpMessage = TcpMessage.Decode(bytes); + var binaryReader = new BinaryReader(new MemoryStream(tcpMessage.Body, false)); + var a = binaryReader.ReadInt64(); + var msgId = binaryReader.ReadInt64(); + var datalength = binaryReader.ReadInt32(); + var data = binaryReader.ReadBytes(datalength); + + var binaryReader2 = new BinaryReader(new MemoryStream(data, false)); + const int responseConstructorNumber = 0x60469778; + var responseCode = binaryReader2.ReadInt32(); + Console.WriteLine("Request code: " + responseCode); + if (responseCode == responseConstructorNumber)//---Step1_PQRequest + { + nonceFromClient = binaryReader2.ReadBytes(16); + } + + var nonce = new byte[16]; + new Random().NextBytes(nonce); + + var fingerprint = StringToByteArray("216be86c022bb4c3"); + //var rr = BitConverter.ToString(fingerprint).Replace("-", ""); + + var step1 = new Step1_Response() + { + Pq = new BigInteger(1, BitConverter.GetBytes(880)), + ServerNonce = nonceFromClient, + Nonce = nonce, + Fingerprints = new List() { fingerprint } + }; + var bytes1 = PrepareToSend(step1.ToBytes()); + var datatosend = Encode(bytes1, 11); + //Byte[] sendBytes = Encoding.UTF8.GetBytes("Is anybody there?"); + tcpClient.Send(datatosend, SocketFlags.Truncated); + + //tcpClient.Close(); + } + + public static async Task Receieve(TcpClient tcpClient) + { + var stream = tcpClient.GetStream(); + + var packetLengthBytes = new byte[4]; + if (await stream.ReadAsync(packetLengthBytes, 0, 4) != 4) + throw new InvalidOperationException("Couldn't read the packet length"); + int packetLength = BitConverter.ToInt32(packetLengthBytes, 0); + + var seqBytes = new byte[4]; + if (await stream.ReadAsync(seqBytes, 0, 4) != 4) + throw new InvalidOperationException("Couldn't read the sequence"); + int seq = BitConverter.ToInt32(seqBytes, 0); + + int readBytes = 0; + var body = new byte[packetLength - 12]; + int neededToRead = packetLength - 12; + + do + { + var bodyByte = new byte[packetLength - 12]; + var availableBytes = await stream.ReadAsync(bodyByte, 0, neededToRead); + neededToRead -= availableBytes; + Buffer.BlockCopy(bodyByte, 0, body, readBytes, availableBytes); + readBytes += availableBytes; + } + while (readBytes != packetLength - 12); + + var crcBytes = new byte[4]; + if (await stream.ReadAsync(crcBytes, 0, 4) != 4) + throw new InvalidOperationException("Couldn't read the crc"); + int checksum = BitConverter.ToInt32(crcBytes, 0); + + byte[] rv = new byte[packetLengthBytes.Length + seqBytes.Length + body.Length]; + + Buffer.BlockCopy(packetLengthBytes, 0, rv, 0, packetLengthBytes.Length); + Buffer.BlockCopy(seqBytes, 0, rv, packetLengthBytes.Length, seqBytes.Length); + Buffer.BlockCopy(body, 0, rv, packetLengthBytes.Length + seqBytes.Length, body.Length); + var crc32 = new Ionic.Crc.CRC32(); + crc32.SlurpBlock(rv, 0, rv.Length); + var validChecksum = crc32.Crc32Result; + + if (checksum != validChecksum) + { + throw new InvalidOperationException("invalid checksum! skip"); + } + + return new TcpMessage(seq, body); + } + + public static byte[] PrepareToSend(byte[] data) + { + using (var memoryStream = new MemoryStream()) + { + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write((long)0); + binaryWriter.Write(GetNewMessageId()); + binaryWriter.Write(data.Length); + binaryWriter.Write(data); + + byte[] packet = memoryStream.ToArray(); + + return packet; + } + } + } + + private static long GetNewMessageId() + { + long time = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds); + long newMessageId = ((time / 1000 + timeOffset) << 32) | + ((time % 1000) << 22) | + (random.Next(524288) << 2); // 2^19 + // [ unix timestamp : 32 bit] [ milliseconds : 10 bit ] [ buffer space : 1 bit ] [ random : 19 bit ] [ msg_id type : 2 bit ] = [ msg_id : 64 bit ] + + if (lastMessageId >= newMessageId) + { + newMessageId = lastMessageId + 4; + } + + lastMessageId = newMessageId; + return newMessageId; + } + + private static Tuple DecodeMessage(byte[] body) + { + byte[] message; + ulong remoteMessageId; + int remoteSequence; + + using (var inputStream = new MemoryStream(body)) + using (var inputReader = new BinaryReader(inputStream)) + { + if (inputReader.BaseStream.Length < 8) + throw new InvalidOperationException($"Can't decode packet"); + + ulong remoteAuthKeyId = inputReader.ReadUInt64(); // TODO: check auth key id + byte[] msgKey = inputReader.ReadBytes(16); // TODO: check msg_key correctness + AESKeyData keyData = Helpers.CalcKey(body, msgKey, false); + + byte[] plaintext = AES.DecryptAES(keyData, inputReader.ReadBytes((int)(inputStream.Length - inputStream.Position))); + + using (MemoryStream plaintextStream = new MemoryStream(plaintext)) + using (BinaryReader plaintextReader = new BinaryReader(plaintextStream)) + { + var remoteSalt = plaintextReader.ReadUInt64(); + var remoteSessionId = plaintextReader.ReadUInt64(); + remoteMessageId = plaintextReader.ReadUInt64(); + remoteSequence = plaintextReader.ReadInt32(); + int msgLen = plaintextReader.ReadInt32(); + message = plaintextReader.ReadBytes(msgLen); + } + } + return new Tuple(message, remoteMessageId, remoteSequence); + } + + private static byte[] Encode(byte[] body, int sequneceNumber) + { + using (var memoryStream = new MemoryStream()) + { + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + // https://core.telegram.org/mtproto#tcp-transport + /* + 4 length bytes are added at the front + (to include the length, the sequence number, and CRC32; always divisible by 4) + and 4 bytes with the packet sequence number within this TCP connection + (the first packet sent is numbered 0, the next one 1, etc.), + and 4 CRC32 bytes at the end (length, sequence number, and payload together). + */ + binaryWriter.Write(body.Length + 12); + binaryWriter.Write(sequneceNumber); + binaryWriter.Write(body); + var crc32 = new CRC32(); + crc32.SlurpBlock(memoryStream.GetBuffer(), 0, 8 + body.Length); + binaryWriter.Write(crc32.Crc32Result); + + var transportPacket = memoryStream.ToArray(); + + // Debug.WriteLine("Tcp packet #{0}\n{1}", SequneceNumber, BitConverter.ToString(transportPacket)); + + return transportPacket; + } + } + } + + public static T FromByteArray(byte[] data) + { + if (data == null) + return default(T); + var bf = new BinaryFormatter(); + using (var ms = new MemoryStream(data)) + { + var obj = bf.Deserialize(ms); + return (T)obj; + } + } + + public static byte[] StringToByteArray(string hex) + { + return Enumerable.Range(0, hex.Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) + .ToArray(); + } + } +} diff --git a/Apps/TlgListenerApplication/Properties/AssemblyInfo.cs b/Apps/TlgListenerApplication/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..519e112 --- /dev/null +++ b/Apps/TlgListenerApplication/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TlgListenerApplication")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TlgListenerApplication")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("15f1cfa2-e099-48fd-97e7-be06aa5b3ea6")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Apps/TlgListenerApplication/TlgListenerApplication.csproj b/Apps/TlgListenerApplication/TlgListenerApplication.csproj new file mode 100644 index 0000000..9dfe9e9 --- /dev/null +++ b/Apps/TlgListenerApplication/TlgListenerApplication.csproj @@ -0,0 +1,66 @@ + + + + + Debug + AnyCPU + {15F1CFA2-E099-48FD-97E7-BE06AA5B3EA6} + Exe + TlgListenerApplication + TlgListenerApplication + v4.6 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\MarkerMetro.Unity.Ionic.Zlib.2.0.0.14\lib\net35\Ionic.ZLib.dll + + + + + + + + + + + + + + + + + + + + + {d6144517-91d2-4880-86df-e9ff5d7f383a} + TeleSharp.TL + + + {400d2544-1cc6-4d8a-a62c-2292d9947a16} + TLSharp.Core + + + + \ No newline at end of file diff --git a/Apps/TlgListenerApplication/packages.config b/Apps/TlgListenerApplication/packages.config new file mode 100644 index 0000000..a6d41ac --- /dev/null +++ b/Apps/TlgListenerApplication/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/TLSharp.Core/Auth/Step1_PQRequest.cs b/TLSharp.Core/Auth/Step1_PQRequest.cs index 8d61d9a..24c97c1 100644 --- a/TLSharp.Core/Auth/Step1_PQRequest.cs +++ b/TLSharp.Core/Auth/Step1_PQRequest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using TLSharp.Core.MTProto; using TLSharp.Core.MTProto.Crypto; @@ -9,10 +10,43 @@ namespace TLSharp.Core.Auth { public class Step1_Response { + public Step1_Response() + { + Nonce = new byte[16]; + ServerNonce = new byte[16]; + } + public byte[] Nonce { get; set; } public byte[] ServerNonce { get; set; } public BigInteger Pq { get; set; } public List Fingerprints { get; set; } + + public byte[] ToBytes() + { + new Random().NextBytes(Nonce); + const int constructorNumber = 0x05162463; + const int vectorConstructorNumber = 0x1cb5c415; + + + using (var memoryStream = new MemoryStream()) + { + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(constructorNumber); + binaryWriter.Write(ServerNonce); + binaryWriter.Write(Nonce); + Serializers.Bytes.write(binaryWriter, Pq.ToByteArrayUnsigned()); + binaryWriter.Write(vectorConstructorNumber); + binaryWriter.Write(Fingerprints.Count); + foreach (var fingerprint in Fingerprints) + { + binaryWriter.Write(fingerprint); + } + + return memoryStream.ToArray(); + } + } + } } public class Step1_PQRequest @@ -62,7 +96,6 @@ namespace TLSharp.Core.Auth { throw new InvalidOperationException("invalid nonce from server"); } - var serverNonce = binaryReader.ReadBytes(16); byte[] pqbytes = Serializers.Bytes.read(binaryReader); @@ -92,5 +125,6 @@ namespace TLSharp.Core.Auth } } } + } } diff --git a/TLSharp.Core/Auth/Step2_DHExchange.cs b/TLSharp.Core/Auth/Step2_DHExchange.cs index 53b8016..0abb63c 100644 --- a/TLSharp.Core/Auth/Step2_DHExchange.cs +++ b/TLSharp.Core/Auth/Step2_DHExchange.cs @@ -12,6 +12,25 @@ namespace TLSharp.Core.Auth public byte[] ServerNonce { get; set; } public byte[] NewNonce { get; set; } public byte[] EncryptedAnswer { get; set; } + + public byte[] ToBytes() + { + const uint constructorNumber = 0xd0e8075c; + + using (var memoryStream = new MemoryStream()) + { + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(constructorNumber); + binaryWriter.Write(ServerNonce); + binaryWriter.Write(Nonce); + //binaryWriter.Write(EncryptedAnswer); + Serializers.Bytes.write(binaryWriter, EncryptedAnswer); + + return memoryStream.ToArray(); + } + } + } } public class Step2_DHExchange @@ -48,7 +67,7 @@ namespace TLSharp.Core.Auth foreach (byte[] fingerprint in fingerprints) { ciphertext = RSA.Encrypt(BitConverter.ToString(fingerprint).Replace("-", string.Empty), - pqInnerData.GetBuffer(), 0, (int)pqInnerData.Position); + pqInnerData.GetBuffer(), 0, (int)pqInnerData.Position); if (ciphertext != null) { targetFingerprint = fingerprint; diff --git a/TLSharp.Core/Auth/Step3_CompleteDHExchange.cs b/TLSharp.Core/Auth/Step3_CompleteDHExchange.cs index 8ba8f5a..c6c9a41 100644 --- a/TLSharp.Core/Auth/Step3_CompleteDHExchange.cs +++ b/TLSharp.Core/Auth/Step3_CompleteDHExchange.cs @@ -11,7 +11,6 @@ namespace TLSharp.Core.Auth { public AuthKey AuthKey { get; set; } public int TimeOffset { get; set; } - } public class Step3_CompleteDHExchange diff --git a/TLSharp.Core/Network/MtProtoSender.cs b/TLSharp.Core/Network/MtProtoSender.cs index 795e878..c3e1737 100644 --- a/TLSharp.Core/Network/MtProtoSender.cs +++ b/TLSharp.Core/Network/MtProtoSender.cs @@ -319,6 +319,10 @@ namespace TLSharp.Core.Network { throw new CloudPasswordNeededException("This Account has Cloud Password !"); } + else if (errorMessage == "MESSAGE_ID_INVALID") + { + throw new InvalidOperationException("The provided message id is invalid " + errorMessage); + } else { throw new InvalidOperationException(errorMessage); @@ -548,7 +552,7 @@ namespace TLSharp.Core.Network private const string REPORT_MESSAGE = " See: https://github.com/sochix/TLSharp#i-get-a-xxxmigrationexception-or-a-migrate_x-error"; - protected DataCenterMigrationException(string msg, int dc) : base (msg + REPORT_MESSAGE) + protected DataCenterMigrationException(string msg, int dc) : base(msg + REPORT_MESSAGE) { DC = dc; } @@ -557,7 +561,7 @@ namespace TLSharp.Core.Network internal class PhoneMigrationException : DataCenterMigrationException { internal PhoneMigrationException(int dc) - : base ($"Phone number registered to a different DC: {dc}.", dc) + : base($"Phone number registered to a different DC: {dc}.", dc) { } } @@ -565,7 +569,7 @@ namespace TLSharp.Core.Network internal class FileMigrationException : DataCenterMigrationException { internal FileMigrationException(int dc) - : base ($"File located on a different DC: {dc}.", dc) + : base($"File located on a different DC: {dc}.", dc) { } } @@ -577,7 +581,7 @@ namespace TLSharp.Core.Network { } } - + internal class NetworkMigrationException : DataCenterMigrationException { internal NetworkMigrationException(int dc) diff --git a/TLSharp.Core/Network/TcpTransport.cs b/TLSharp.Core/Network/TcpTransport.cs index 31bd6b4..4ba997f 100644 --- a/TLSharp.Core/Network/TcpTransport.cs +++ b/TLSharp.Core/Network/TcpTransport.cs @@ -1,89 +1,91 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading.Tasks; - -namespace TLSharp.Core.Network -{ - public delegate TcpClient TcpClientConnectionHandler(string address, int port); - - public class TcpTransport : IDisposable - { - private readonly TcpClient _tcpClient; - private int sendCounter = 0; - - public TcpTransport(string address, int port, TcpClientConnectionHandler handler = null) - { - if (handler == null) - { - _tcpClient = new TcpClient(); - - var ipAddress = IPAddress.Parse(address); - _tcpClient.Connect(ipAddress, port); - } - else - _tcpClient = handler(address, port); - } - - public async Task Send(byte[] packet) - { - if (!_tcpClient.Connected) - throw new InvalidOperationException("Client not connected to server."); - - var tcpMessage = new TcpMessage(sendCounter, packet); - - await _tcpClient.GetStream().WriteAsync(tcpMessage.Encode(), 0, tcpMessage.Encode().Length); - sendCounter++; - } - - public async Task Receieve() - { - var stream = _tcpClient.GetStream(); - - var packetLengthBytes = new byte[4]; - if (await stream.ReadAsync(packetLengthBytes, 0, 4) != 4) - throw new InvalidOperationException("Couldn't read the packet length"); - int packetLength = BitConverter.ToInt32(packetLengthBytes, 0); - - var seqBytes = new byte[4]; - if (await stream.ReadAsync(seqBytes, 0, 4) != 4) - throw new InvalidOperationException("Couldn't read the sequence"); - int seq = BitConverter.ToInt32(seqBytes, 0); - - int readBytes = 0; - var body = new byte[packetLength - 12]; - int neededToRead = packetLength - 12; - - do - { - var bodyByte = new byte[packetLength - 12]; - var availableBytes = await stream.ReadAsync(bodyByte, 0, neededToRead); - neededToRead -= availableBytes; - Buffer.BlockCopy(bodyByte, 0, body, readBytes, availableBytes); - readBytes += availableBytes; - } - while (readBytes != packetLength - 12); - - var crcBytes = new byte[4]; - if (await stream.ReadAsync(crcBytes, 0, 4) != 4) - throw new InvalidOperationException("Couldn't read the crc"); - int checksum = BitConverter.ToInt32(crcBytes, 0); - - byte[] rv = new byte[packetLengthBytes.Length + seqBytes.Length + body.Length]; - - Buffer.BlockCopy(packetLengthBytes, 0, rv, 0, packetLengthBytes.Length); - Buffer.BlockCopy(seqBytes, 0, rv, packetLengthBytes.Length, seqBytes.Length); - Buffer.BlockCopy(body, 0, rv, packetLengthBytes.Length + seqBytes.Length, body.Length); - var crc32 = new Ionic.Crc.CRC32(); - crc32.SlurpBlock(rv, 0, rv.Length); - var validChecksum = crc32.Crc32Result; - - if (checksum != validChecksum) - { - throw new InvalidOperationException("invalid checksum! skip"); - } - - return new TcpMessage(seq, body); +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace TLSharp.Core.Network +{ + public delegate TcpClient TcpClientConnectionHandler(string address, int port); + + public class TcpTransport : IDisposable + { + private readonly TcpClient _tcpClient; + private int sendCounter = 0; + + public TcpTransport(string address, int port, TcpClientConnectionHandler handler = null) + { + if (handler == null) + { + _tcpClient = new TcpClient(); + + _tcpClient.Connect(IPAddress.Parse(address), port); + } + else + _tcpClient = handler(address, port); + } + + public async Task Send(byte[] packet) + { + if (!_tcpClient.Connected) + throw new InvalidOperationException("Client not connected to server."); + + var tcpMessage = new TcpMessage(sendCounter, packet); + + await _tcpClient.GetStream().WriteAsync(tcpMessage.Encode(), 0, tcpMessage.Encode().Length); + sendCounter++; + } + + public async Task Receieve() + { + if (!_tcpClient.Connected) + throw new InvalidOperationException("Client not connected to server."); + + var stream = _tcpClient.GetStream(); + + var packetLengthBytes = new byte[4]; + if (await stream.ReadAsync(packetLengthBytes, 0, 4) != 4) + throw new InvalidOperationException("Couldn't read the packet length"); + int packetLength = BitConverter.ToInt32(packetLengthBytes, 0); + + var seqBytes = new byte[4]; + if (await stream.ReadAsync(seqBytes, 0, 4) != 4) + throw new InvalidOperationException("Couldn't read the sequence"); + int seq = BitConverter.ToInt32(seqBytes, 0); + + int readBytes = 0; + var body = new byte[packetLength - 12]; + int neededToRead = packetLength - 12; + + do + { + var bodyByte = new byte[packetLength - 12]; + var availableBytes = await stream.ReadAsync(bodyByte, 0, neededToRead); + neededToRead -= availableBytes; + Buffer.BlockCopy(bodyByte, 0, body, readBytes, availableBytes); + readBytes += availableBytes; + } + while (readBytes != packetLength - 12); + + var crcBytes = new byte[4]; + if (await stream.ReadAsync(crcBytes, 0, 4) != 4) + throw new InvalidOperationException("Couldn't read the crc"); + int checksum = BitConverter.ToInt32(crcBytes, 0); + + byte[] rv = new byte[packetLengthBytes.Length + seqBytes.Length + body.Length]; + + Buffer.BlockCopy(packetLengthBytes, 0, rv, 0, packetLengthBytes.Length); + Buffer.BlockCopy(seqBytes, 0, rv, packetLengthBytes.Length, seqBytes.Length); + Buffer.BlockCopy(body, 0, rv, packetLengthBytes.Length + seqBytes.Length, body.Length); + var crc32 = new Ionic.Crc.CRC32(); + crc32.SlurpBlock(rv, 0, rv.Length); + var validChecksum = crc32.Crc32Result; + + if (checksum != validChecksum) + { + throw new InvalidOperationException("invalid checksum! skip"); + } + + return new TcpMessage(seq, body); } public bool IsConnected @@ -95,10 +97,10 @@ namespace TLSharp.Core.Network } - public void Dispose() - { - if (_tcpClient.Connected) - _tcpClient.Close(); + public void Dispose() + { + if (_tcpClient.Connected) + _tcpClient.Close(); } - } -} + } +} diff --git a/TLSharp.Core/Session.cs b/TLSharp.Core/Session.cs index 987c5d2..cb7c61e 100644 --- a/TLSharp.Core/Session.cs +++ b/TLSharp.Core/Session.cs @@ -54,9 +54,9 @@ namespace TLSharp.Core public class Session { - private const string defaultConnectionAddress = "149.154.175.100";//"149.154.167.50"; + private const string defaultConnectionAddress = "149.154.175.100";//"149.154.167.50"; - private const int defaultConnectionPort = 443; + private const int defaultConnectionPort = 443; public string SessionUserId { get; set; } public string ServerAddress { get; set; } @@ -155,14 +155,14 @@ namespace TLSharp.Core _store.Save(this); } - public static Session TryLoadOrCreateNew(ISessionStore store, string sessionUserId) + public static Session TryLoadOrCreateNew(ISessionStore store, string sessionUserId, string serverAddress = "", int? serverPort = null) { return store.Load(sessionUserId) ?? new Session(store) { Id = GenerateRandomUlong(), SessionUserId = sessionUserId, - ServerAddress = defaultConnectionAddress, - Port = defaultConnectionPort + ServerAddress = string.IsNullOrEmpty(serverAddress) ? defaultConnectionAddress : serverAddress, + Port = serverPort ?? defaultConnectionPort }; } @@ -179,7 +179,7 @@ namespace TLSharp.Core long newMessageId = ((time / 1000 + TimeOffset) << 32) | ((time % 1000) << 22) | (random.Next(524288) << 2); // 2^19 - // [ unix timestamp : 32 bit] [ milliseconds : 10 bit ] [ buffer space : 1 bit ] [ random : 19 bit ] [ msg_id type : 2 bit ] = [ msg_id : 64 bit ] + // [ unix timestamp : 32 bit] [ milliseconds : 10 bit ] [ buffer space : 1 bit ] [ random : 19 bit ] [ msg_id type : 2 bit ] = [ msg_id : 64 bit ] if (LastMessageId >= newMessageId) { diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index 0692486..4cd7c9d 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -1,90 +1,90 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using TeleSharp.TL; -using TeleSharp.TL.Account; -using TeleSharp.TL.Auth; -using TeleSharp.TL.Contacts; -using TeleSharp.TL.Help; -using TeleSharp.TL.Messages; -using TeleSharp.TL.Upload; -using TLSharp.Core.Auth; -using TLSharp.Core.MTProto.Crypto; -using TLSharp.Core.Network; -using TLSharp.Core.Utils; -using TLAuthorization = TeleSharp.TL.Auth.TLAuthorization; - -namespace TLSharp.Core -{ - public class TelegramClient : IDisposable - { - private MtProtoSender _sender; - private AuthKey _key; - private TcpTransport _transport; - private string _apiHash = ""; - private int _apiId = 0; - private Session _session; - private List dcOptions; - private TcpClientConnectionHandler _handler; - - public TelegramClient(int apiId, string apiHash, - ISessionStore store = null, string sessionUserId = "session", TcpClientConnectionHandler handler = null) - { - if (apiId == default(int)) - throw new MissingApiConfigurationException("API_ID"); - if (string.IsNullOrEmpty(apiHash)) - throw new MissingApiConfigurationException("API_HASH"); - - if (store == null) - store = new FileSessionStore(); - - TLContext.Init(); - _apiHash = apiHash; - _apiId = apiId; - _handler = handler; - - _session = Session.TryLoadOrCreateNew(store, sessionUserId); - _transport = new TcpTransport(_session.ServerAddress, _session.Port, _handler); - } - - public async Task ConnectAsync(bool reconnect = false) - { - if (_session.AuthKey == null || reconnect) - { - var result = await Authenticator.DoAuthentication(_transport); - _session.AuthKey = result.AuthKey; - _session.TimeOffset = result.TimeOffset; - } - - _sender = new MtProtoSender(_transport, _session); - - //set-up layer - var config = new TLRequestGetConfig(); - var request = new TLRequestInitConnection() - { - ApiId = _apiId, - AppVersion = "1.0.0", - DeviceModel = "PC", - LangCode = "en", - Query = config, - SystemVersion = "Win 10.0" - }; - var invokewithLayer = new TLRequestInvokeWithLayer() { Layer = 66, Query = request }; - await _sender.Send(invokewithLayer); - await _sender.Receive(invokewithLayer); - - dcOptions = ((TLConfig)invokewithLayer.Response).DcOptions.ToList(); - - return true; - } - - private async Task ReconnectToDcAsync(int dcId) - { - if (dcOptions == null || !dcOptions.Any()) - throw new InvalidOperationException($"Can't reconnect. Establish initial connection first."); +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using TeleSharp.TL; +using TeleSharp.TL.Account; +using TeleSharp.TL.Auth; +using TeleSharp.TL.Contacts; +using TeleSharp.TL.Help; +using TeleSharp.TL.Messages; +using TeleSharp.TL.Upload; +using TLSharp.Core.Auth; +using TLSharp.Core.MTProto.Crypto; +using TLSharp.Core.Network; +using TLSharp.Core.Utils; +using TLAuthorization = TeleSharp.TL.Auth.TLAuthorization; + +namespace TLSharp.Core +{ + public class TelegramClient : IDisposable + { + private MtProtoSender _sender; + private AuthKey _key; + private TcpTransport _transport; + private string _apiHash = ""; + private int _apiId = 0; + private Session _session; + private List dcOptions; + private TcpClientConnectionHandler _handler; + + public TelegramClient(int apiId, string apiHash, + ISessionStore store = null, string sessionUserId = "session", TcpClientConnectionHandler handler = null, string serverAddress = "", int? serverPort = null) + { + if (apiId == default(int)) + throw new MissingApiConfigurationException("API_ID"); + if (string.IsNullOrEmpty(apiHash)) + throw new MissingApiConfigurationException("API_HASH"); + + if (store == null) + store = new FileSessionStore(); + + TLContext.Init(); + _apiHash = apiHash; + _apiId = apiId; + _handler = handler; + + _session = Session.TryLoadOrCreateNew(store, sessionUserId, serverAddress, serverPort); + _transport = new TcpTransport(string.IsNullOrEmpty(serverAddress) ? _session.ServerAddress : serverAddress, serverPort ?? _session.Port, _handler); + } + + public async Task ConnectAsync(bool reconnect = false) + { + if (_session.AuthKey == null || reconnect) + { + var result = await Authenticator.DoAuthentication(_transport); + _session.AuthKey = result.AuthKey; + _session.TimeOffset = result.TimeOffset; + } + + _sender = new MtProtoSender(_transport, _session); + + //set-up layer + var config = new TLRequestGetConfig(); + var request = new TLRequestInitConnection() + { + ApiId = _apiId, + AppVersion = "1.0.0", + DeviceModel = "PC", + LangCode = "en", + Query = config, + SystemVersion = "Win 10.0" + }; + var invokewithLayer = new TLRequestInvokeWithLayer() { Layer = 66, Query = request }; + await _sender.Send(invokewithLayer); + await _sender.Receive(invokewithLayer); + + dcOptions = ((TLConfig)invokewithLayer.Response).DcOptions.ToList(); + + return true; + } + + private async Task ReconnectToDcAsync(int dcId) + { + if (dcOptions == null || !dcOptions.Any()) + throw new InvalidOperationException($"Can't reconnect. Establish initial connection first."); TLExportedAuthorization exported = null; if (_session.TLUser != null) @@ -92,13 +92,13 @@ namespace TLSharp.Core TLRequestExportAuthorization exportAuthorization = new TLRequestExportAuthorization() { DcId = dcId }; exported = await SendRequestAsync(exportAuthorization); } - - var dc = dcOptions.First(d => d.Id == dcId); - - _transport = new TcpTransport(dc.IpAddress, dc.Port, _handler); - _session.ServerAddress = dc.IpAddress; - _session.Port = dc.Port; - + + var dc = dcOptions.First(d => d.Id == dcId); + + _transport = new TcpTransport(dc.IpAddress, dc.Port, _handler); + _session.ServerAddress = dc.IpAddress; + _session.Port = dc.Port; + await ConnectAsync(true); if (_session.TLUser != null) @@ -106,214 +106,229 @@ namespace TLSharp.Core TLRequestImportAuthorization importAuthorization = new TLRequestImportAuthorization() { Id = exported.Id, Bytes = exported.Bytes }; var imported = await SendRequestAsync(importAuthorization); OnUserAuthenticated(((TLUser)imported.User)); - } - } - - private async Task RequestWithDcMigration(TLMethod request) - { - var completed = false; - while(!completed) - { - try - { - await _sender.Send(request); - await _sender.Receive(request); - completed = true; - } - catch(DataCenterMigrationException e) - { - await ReconnectToDcAsync(e.DC); - // prepare the request for another try - request.ConfirmReceived = false; - } } - } - - public bool IsUserAuthorized() - { - return _session.TLUser != null; - } - - public async Task IsPhoneRegisteredAsync(string phoneNumber) - { - if (String.IsNullOrWhiteSpace(phoneNumber)) - throw new ArgumentNullException(nameof(phoneNumber)); - - if (_sender == null) - throw new InvalidOperationException("Not connected!"); - - var authCheckPhoneRequest = new TLRequestCheckPhone() { PhoneNumber = phoneNumber }; - - await RequestWithDcMigration(authCheckPhoneRequest); - - return authCheckPhoneRequest.Response.PhoneRegistered; - } - - public async Task SendCodeRequestAsync(string phoneNumber) - { - if (String.IsNullOrWhiteSpace(phoneNumber)) - throw new ArgumentNullException(nameof(phoneNumber)); - - var request = new TLRequestSendCode() { PhoneNumber = phoneNumber, ApiId = _apiId, ApiHash = _apiHash }; - - await RequestWithDcMigration(request); - - return request.Response.PhoneCodeHash; - } - - public async Task MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code) - { - if (String.IsNullOrWhiteSpace(phoneNumber)) - throw new ArgumentNullException(nameof(phoneNumber)); - - if (String.IsNullOrWhiteSpace(phoneCodeHash)) - throw new ArgumentNullException(nameof(phoneCodeHash)); - - if (String.IsNullOrWhiteSpace(code)) - throw new ArgumentNullException(nameof(code)); - + } + + private async Task RequestWithDcMigration(TLMethod request) + { + var completed = false; + while (!completed) + { + try + { + await _sender.Send(request); + await _sender.Receive(request); + completed = true; + } + catch (DataCenterMigrationException e) + { + await ReconnectToDcAsync(e.DC); + // prepare the request for another try + request.ConfirmReceived = false; + } + } + } + + public bool IsUserAuthorized() + { + return _session.TLUser != null; + } + + public async Task IsPhoneRegisteredAsync(string phoneNumber) + { + if (String.IsNullOrWhiteSpace(phoneNumber)) + throw new ArgumentNullException(nameof(phoneNumber)); + + if (_sender == null) + throw new InvalidOperationException("Not connected!"); + + var authCheckPhoneRequest = new TLRequestCheckPhone() { PhoneNumber = phoneNumber }; + + await RequestWithDcMigration(authCheckPhoneRequest); + + return authCheckPhoneRequest.Response.PhoneRegistered; + } + + public async Task SendCodeRequestAsync(string phoneNumber) + { + if (String.IsNullOrWhiteSpace(phoneNumber)) + throw new ArgumentNullException(nameof(phoneNumber)); + + var request = new TLRequestSendCode() { PhoneNumber = phoneNumber, ApiId = _apiId, ApiHash = _apiHash }; + + await RequestWithDcMigration(request); + + return request.Response.PhoneCodeHash; + } + + public async Task MakeAuthAsync(string phoneNumber, string phoneCodeHash, string code) + { + if (String.IsNullOrWhiteSpace(phoneNumber)) + throw new ArgumentNullException(nameof(phoneNumber)); + + if (String.IsNullOrWhiteSpace(phoneCodeHash)) + throw new ArgumentNullException(nameof(phoneCodeHash)); + + if (String.IsNullOrWhiteSpace(code)) + throw new ArgumentNullException(nameof(code)); + var request = new TLRequestSignIn() { PhoneNumber = phoneNumber, PhoneCodeHash = phoneCodeHash, PhoneCode = code }; - await RequestWithDcMigration(request); - - OnUserAuthenticated(((TLUser)request.Response.User)); - - return ((TLUser)request.Response.User); - } - - public async Task GetPasswordSetting() - { - var request = new TLRequestGetPassword(); - - await RequestWithDcMigration(request); - - return ((TLPassword)request.Response); - } - - public async Task MakeAuthWithPasswordAsync(TLPassword password, string password_str) - { - - byte[] password_Bytes = Encoding.UTF8.GetBytes(password_str); - IEnumerable rv = password.CurrentSalt.Concat(password_Bytes).Concat(password.CurrentSalt); - - SHA256Managed hashstring = new SHA256Managed(); - var password_hash = hashstring.ComputeHash(rv.ToArray()); - - var request = new TLRequestCheckPassword() { PasswordHash = password_hash }; - - await RequestWithDcMigration(request); - - OnUserAuthenticated(((TLUser)request.Response.User)); - - return ((TLUser)request.Response.User); - } - - public async Task SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName) - { - var request = new TLRequestSignUp() { PhoneNumber = phoneNumber, PhoneCode = code, PhoneCodeHash = phoneCodeHash, FirstName = firstName, LastName = lastName }; - - await RequestWithDcMigration(request); - - OnUserAuthenticated(((TLUser)request.Response.User)); - - return ((TLUser)request.Response.User); - } - public async Task SendRequestAsync(TLMethod methodToExecute) - { - await RequestWithDcMigration(methodToExecute); - - var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute); - - return (T)result; - } - - public async Task GetContactsAsync() - { - if (!IsUserAuthorized()) - throw new InvalidOperationException("Authorize user first!"); - - var req = new TLRequestGetContacts() { Hash = "" }; - - return await SendRequestAsync(req); - } - - public async Task SendMessageAsync(TLAbsInputPeer peer, string message) - { - if (!IsUserAuthorized()) - throw new InvalidOperationException("Authorize user first!"); - - return await SendRequestAsync( - new TLRequestSendMessage() - { - Peer = peer, - Message = message, - RandomId = Helpers.GenerateRandomLong() - }); - } - - public async Task SendTypingAsync(TLAbsInputPeer peer) - { - var req = new TLRequestSetTyping() - { - Action = new TLSendMessageTypingAction(), - Peer = peer - }; - return await SendRequestAsync(req); - } - - public async Task GetUserDialogsAsync() - { - var peer = new TLInputPeerSelf(); - return await SendRequestAsync( - new TLRequestGetDialogs() { OffsetDate = 0, OffsetPeer = peer, Limit = 100 }); - } - - public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption) - { - return await SendRequestAsync(new TLRequestSendMedia() - { - RandomId = Helpers.GenerateRandomLong(), - Background = false, - ClearDraft = false, - Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, - Peer = peer - }); - } - - public async Task SendUploadedDocument( - TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes) - { - return await SendRequestAsync(new TLRequestSendMedia() - { - RandomId = Helpers.GenerateRandomLong(), - Background = false, - ClearDraft = false, - Media = new TLInputMediaUploadedDocument() - { - File = file, - Caption = caption, - MimeType = mimeType, - Attributes = attributes - }, - Peer = peer - }); - } - - public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0) - { - TLFile result = null; - result = await SendRequestAsync(new TLRequestGetFile() - { - Location = location, - Limit = filePartSize, - Offset = offset - }); - return result; - } - - public async Task SendPingAsync() - { - await _sender.SendPingAsync(); + await RequestWithDcMigration(request); + + OnUserAuthenticated(((TLUser)request.Response.User)); + + return ((TLUser)request.Response.User); + } + + public async Task GetPasswordSetting() + { + var request = new TLRequestGetPassword(); + + await RequestWithDcMigration(request); + + return ((TLPassword)request.Response); + } + + public async Task MakeAuthWithPasswordAsync(TLPassword password, string password_str) + { + + byte[] password_Bytes = Encoding.UTF8.GetBytes(password_str); + IEnumerable rv = password.CurrentSalt.Concat(password_Bytes).Concat(password.CurrentSalt); + + SHA256Managed hashstring = new SHA256Managed(); + var password_hash = hashstring.ComputeHash(rv.ToArray()); + + var request = new TLRequestCheckPassword() { PasswordHash = password_hash }; + + await RequestWithDcMigration(request); + + OnUserAuthenticated(((TLUser)request.Response.User)); + + return ((TLUser)request.Response.User); + } + + public async Task SignUpAsync(string phoneNumber, string phoneCodeHash, string code, string firstName, string lastName) + { + var request = new TLRequestSignUp() { PhoneNumber = phoneNumber, PhoneCode = code, PhoneCodeHash = phoneCodeHash, FirstName = firstName, LastName = lastName }; + + await RequestWithDcMigration(request); + + OnUserAuthenticated(((TLUser)request.Response.User)); + + return ((TLUser)request.Response.User); + } + public async Task SendRequestAsync(TLMethod methodToExecute) + { + await RequestWithDcMigration(methodToExecute); + + var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute); + + return (T)result; + } + + public async Task GetContactsAsync() + { + if (!IsUserAuthorized()) + throw new InvalidOperationException("Authorize user first!"); + + var req = new TLRequestGetContacts() { Hash = "" }; + + return await SendRequestAsync(req); + } + + public async Task SendMessageAsync(TLAbsInputPeer peer, string message) + { + if (!IsUserAuthorized()) + throw new InvalidOperationException("Authorize user first!"); + + return await SendRequestAsync( + new TLRequestSendMessage() + { + Peer = peer, + Message = message, + RandomId = Helpers.GenerateRandomLong() + }); + } + + public async Task ForwardMessageAsync(TLAbsInputPeer target, int messageId) + { + if (!IsUserAuthorized()) + throw new InvalidOperationException("Authorize user first!"); + + return await SendRequestAsync( + new TLRequestForwardMessage() + { + Peer = target, + Id = messageId, + RandomId = Helpers.GenerateRandomLong() + }); + } + + + public async Task SendTypingAsync(TLAbsInputPeer peer) + { + var req = new TLRequestSetTyping() + { + Action = new TLSendMessageTypingAction(), + Peer = peer + }; + return await SendRequestAsync(req); + } + + public async Task GetUserDialogsAsync() + { + var peer = new TLInputPeerSelf(); + return await SendRequestAsync( + new TLRequestGetDialogs() { OffsetDate = 0, OffsetPeer = peer, Limit = 100 }); + } + + public async Task SendUploadedPhoto(TLAbsInputPeer peer, TLAbsInputFile file, string caption) + { + return await SendRequestAsync(new TLRequestSendMedia() + { + RandomId = Helpers.GenerateRandomLong(), + Background = false, + ClearDraft = false, + Media = new TLInputMediaUploadedPhoto() { File = file, Caption = caption }, + Peer = peer + }); + } + + public async Task SendUploadedDocument( + TLAbsInputPeer peer, TLAbsInputFile file, string caption, string mimeType, TLVector attributes) + { + return await SendRequestAsync(new TLRequestSendMedia() + { + RandomId = Helpers.GenerateRandomLong(), + Background = false, + ClearDraft = false, + Media = new TLInputMediaUploadedDocument() + { + File = file, + Caption = caption, + MimeType = mimeType, + Attributes = attributes + }, + Peer = peer + }); + } + + public async Task GetFile(TLAbsInputFileLocation location, int filePartSize, int offset = 0) + { + TLFile result = null; + result = await SendRequestAsync(new TLRequestGetFile() + { + Location = location, + Limit = filePartSize, + Offset = offset + }); + return result; + } + + public async Task SendPingAsync() + { + await _sender.SendPingAsync(); } public async Task GetHistoryAsync(TLAbsInputPeer peer, int offset, int max_id, int limit) @@ -329,31 +344,31 @@ namespace TLSharp.Core Limit = limit }; return await SendRequestAsync(req); - } - - /// - /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; - /// - /// User or chat name - /// Max result count - /// - public async Task SearchUserAsync(string q, int limit = 10) - { - var r = new TeleSharp.TL.Contacts.TLRequestSearch - { - Q = q, - Limit = limit - }; - - return await SendRequestAsync(r); - } - - private void OnUserAuthenticated(TLUser TLUser) - { - _session.TLUser = TLUser; - _session.SessionExpires = int.MaxValue; - - _session.Save(); + } + + /// + /// Serch user or chat. API: contacts.search#11f812d8 q:string limit:int = contacts.Found; + /// + /// User or chat name + /// Max result count + /// + public async Task SearchUserAsync(string q, int limit = 10) + { + var r = new TeleSharp.TL.Contacts.TLRequestSearch + { + Q = q, + Limit = limit + }; + + return await SendRequestAsync(r); + } + + private void OnUserAuthenticated(TLUser TLUser) + { + _session.TLUser = TLUser; + _session.SessionExpires = int.MaxValue; + + _session.Save(); } public bool IsConnected @@ -366,32 +381,32 @@ namespace TLSharp.Core } } - public void Dispose() - { - if (_transport != null) - { - _transport.Dispose(); - _transport = null; - } - } - } - - public class MissingApiConfigurationException : Exception - { - public const string InfoUrl = "https://github.com/sochix/TLSharp#quick-configuration"; - - internal MissingApiConfigurationException(string invalidParamName) : - base($"Your {invalidParamName} setting is missing. Adjust the configuration first, see {InfoUrl}") - { - } - } - - public class InvalidPhoneCodeException : Exception - { - internal InvalidPhoneCodeException(string msg) : base(msg) { } - } - public class CloudPasswordNeededException : Exception - { - internal CloudPasswordNeededException(string msg) : base(msg) { } - } -} + public void Dispose() + { + if (_transport != null) + { + _transport.Dispose(); + _transport = null; + } + } + } + + public class MissingApiConfigurationException : Exception + { + public const string InfoUrl = "https://github.com/sochix/TLSharp#quick-configuration"; + + internal MissingApiConfigurationException(string invalidParamName) : + base($"Your {invalidParamName} setting is missing. Adjust the configuration first, see {InfoUrl}") + { + } + } + + public class InvalidPhoneCodeException : Exception + { + internal InvalidPhoneCodeException(string msg) : base(msg) { } + } + public class CloudPasswordNeededException : Exception + { + internal CloudPasswordNeededException(string msg) : base(msg) { } + } +} diff --git a/TLSharp.sln b/TLSharp.sln index 4f55f1b..3e47bf8 100644 --- a/TLSharp.sln +++ b/TLSharp.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2002 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TLSharp.Core", "TLSharp.Core\TLSharp.Core.csproj", "{400D2544-1CC6-4D8A-A62C-2292D9947A16}" EndProject @@ -15,6 +15,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TLSharp.Tests.VS", "TLSharp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TLSharp.Tests.NUnit", "TLSharp.Tests.NUnit\TLSharp.Tests.NUnit.csproj", "{E90B705B-19FA-43BA-B952-69957976D12C}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{AECAC38E-472B-4D0A-94F7-C818DC71D3A6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientConsoleApp", "Apps\ClientConsoleApp\ClientConsoleApp.csproj", "{15296FBD-23B9-4786-8CC0-65C872FBFDAC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TlgListenerApplication", "Apps\TlgListenerApplication\TlgListenerApplication.csproj", "{15F1CFA2-E099-48FD-97E7-BE06AA5B3EA6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +51,24 @@ Global {E90B705B-19FA-43BA-B952-69957976D12C}.Debug|Any CPU.Build.0 = Debug|Any CPU {E90B705B-19FA-43BA-B952-69957976D12C}.Release|Any CPU.ActiveCfg = Release|Any CPU {E90B705B-19FA-43BA-B952-69957976D12C}.Release|Any CPU.Build.0 = Release|Any CPU + {15296FBD-23B9-4786-8CC0-65C872FBFDAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15296FBD-23B9-4786-8CC0-65C872FBFDAC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15296FBD-23B9-4786-8CC0-65C872FBFDAC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15296FBD-23B9-4786-8CC0-65C872FBFDAC}.Release|Any CPU.Build.0 = Release|Any CPU + {15F1CFA2-E099-48FD-97E7-BE06AA5B3EA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15F1CFA2-E099-48FD-97E7-BE06AA5B3EA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15F1CFA2-E099-48FD-97E7-BE06AA5B3EA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15F1CFA2-E099-48FD-97E7-BE06AA5B3EA6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {15296FBD-23B9-4786-8CC0-65C872FBFDAC} = {AECAC38E-472B-4D0A-94F7-C818DC71D3A6} + {15F1CFA2-E099-48FD-97E7-BE06AA5B3EA6} = {AECAC38E-472B-4D0A-94F7-C818DC71D3A6} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E4B0D0B6-F353-4A26-91A4-BCE2E1904E06} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 @@ -81,7 +105,4 @@ Global $2.inheritsScope = text/x-csharp $2.scope = text/x-csharp EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection EndGlobal diff --git a/TeleSharp.TL/TL/Messages/TLRequestForwardMessages.cs b/TeleSharp.TL/TL/Messages/TLRequestForwardMessages.cs index ac85f71..ec4edf1 100644 --- a/TeleSharp.TL/TL/Messages/TLRequestForwardMessages.cs +++ b/TeleSharp.TL/TL/Messages/TLRequestForwardMessages.cs @@ -7,6 +7,76 @@ using System.Threading.Tasks; using TeleSharp.TL; namespace TeleSharp.TL.Messages { + //[TLObject(0x708e0195)] + //public class TLRequestForwardMessages : TLMethod + //{ + // // Methods + // public void ComputeFlags() + // { + // this.flags = 0; + // this.flags = this.silent ? (this.flags | 0x20) : (this.flags & -33); + // this.flags = this.background ? (this.flags | 0x40) : (this.flags & -65); + // this.flags = this.with_my_score ? (this.flags | 0x100) : (this.flags & -257); + // } + + // public override void DeserializeBody(BinaryReader br) + // { + // this.flags = br.ReadInt32(); + // this.silent = (this.flags & 0x20) > 0; + // this.background = (this.flags & 0x40) > 0; + // this.with_my_score = (this.flags & 0x100) > 0; + // this.from_peer = (TLAbsInputPeer)ObjectUtils.DeserializeObject(br); + // this.id = ObjectUtils.DeserializeVector(br); + // this.random_id = ObjectUtils.DeserializeVector(br); + // this.to_peer = (TLAbsInputPeer)ObjectUtils.DeserializeObject(br); + // } + + // public override void DeserializeResponse(BinaryReader br) + // { + // this.Response = (TLAbsUpdates)ObjectUtils.DeserializeObject(br); + // } + + // public override void SerializeBody(BinaryWriter bw) + // { + // bw.Write(this.Constructor); + // this.ComputeFlags(); + // bw.Write(this.flags); + // ObjectUtils.SerializeObject(this.from_peer, bw); + // ObjectUtils.SerializeObject(this.id, bw); + // ObjectUtils.SerializeObject(this.random_id, bw); + // ObjectUtils.SerializeObject(this.to_peer, bw); + // } + + // // Properties + // public bool background { get; set; } + + // public override int Constructor + // { + // get + // { + // return 0x708e0195; + // } + // } + + // public int flags { get; set; } + + // public TLAbsInputPeer from_peer { get; set; } + + // public TLVector id { get; set; } + + // public TLVector random_id { get; set; } + + // public TLAbsUpdates Response { get; set; } + + // public bool silent { get; set; } + + // public TLAbsInputPeer to_peer { get; set; } + + // public bool with_my_score { get; set; } + //} + + + [TLObject(1888354709)] public class TLRequestForwardMessages : TLMethod {