How to implement authorization using a Telegram API?

前端 未结 4 925
别那么骄傲
别那么骄傲 2020-11-22 12:27

I want to implement multiple authorization using PHP for interaction with Telegram REST API.

What task am I trying to solve? Well, it\'s simple: several dozens of us

相关标签:
4条回答
  • 2020-11-22 12:51

    As a follow up to my original post, once you are done with the auth_key steps the following will be useful to quickly get you up to speed with how the rest of telegram works.

    1) Download and study the source code for Webogram, it is all basically JavaScript.

    2) run a local copy of Webogram modified with console.logs to clearly show you step by step the interactions that are taking place between "a working telegram client" and the telegram servers. This will give you a work-flow of how telegram clients and Telegram really work.

    3) Use whatever development language you are most comfortable with to build your own implementation of a Protocol Parser for converting binary streams into TL types and vice-versa

    It's actually quite fun to code this step. I've just built a simple Protocol Parser in Elixir

    4) Here is a sample log from a modified copy of Webogram.

    It shows what steps to take after successfully generated your Auth_key

    You even get to see where it has to generate a new Auth_key in-flight as it switches the validated your to the proper DataCenter, recreating his session, new server_salts etc (not shown)

    Regards.

    ID  time    info    log
    121 12:26:35.318    new Auth    Auth successfull! dc= 2 mtproto.js:479:15
    127 12:26:35.325    CALL    =>> API call help.getNearestDc Object {  } Object { dcID: 2, createNetworker: true } mtproto.js:749:4
    128 12:26:35.327    enc-START   [invokeWithLayer] 45 mtproto.js:753:7
    168 12:26:35.551    SEND    POST XHR http://149.154.167.51/apiw1 [HTTP/1.1 200 OK 708ms]
    189 12:26:36.522    msg-r   <<=m [msg_container] Object { _: "msg_container", messages: Array[2] } mtproto.js:1452:5
    190 12:26:36.523    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200678614200321", seqno: 1, bytes: 28, body: Object } mtproto.js:1452:5
    191 12:26:36.525    msg-r   <<=m [new_session_created] Object { _: "new_session_created", first_msg_id: "6242200671500883244", unique_id: "645797764649391412", server_salt: "17212767594123551779" } mtproto.js:1452:5
    192 12:26:36.526    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200678630513665", seqno: 3, bytes: 28, body: Object } mtproto.js:1452:5
    193 12:26:36.528    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200671500883244", result: Object } mtproto.js:1452:5
    257 12:26:39.239    new Auth    Auth successfull! dc= 4 mtproto.js:479:15
    270 12:26:59.606    CALL    =>> API call auth.sendCode Object { phone_number: "2348022002298", sms_type: 5, api_id: 38665, api_hash: "880c7847a517fc455d7d54731e90ad4e", lang_code: "en-US" } Object { dcID: 2, createNetworker: true } mtproto.js:749:4
    321 12:27:00.048    SEND    POST XHR http://149.154.167.51/apiw1 [HTTP/1.1 200 OK 422ms]
    328 12:27:00.981    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200779464550396", result: Object } mtproto.js:1452:5
    331 12:27:00.986    CALL    =>> API call auth.sendCode Object { phone_number: "2348022002298", sms_type: 5, api_id: 38665, api_hash: "880c7847a517fc455d7d54731e90ad4e", lang_code: "en-US" } Object { dcID: "4", createNetworker: true, resultType: "auth.SentCode", messageID: "6242200779464550396" } mtproto.js:749:4
    332 12:27:00.987    enc-START   [invokeWithLayer] 45 mtproto.js:753:7
    377 12:27:01.288    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 321ms]
    398 12:27:02.170    msg-r   <<=m [msg_container] Object { _: "msg_container", messages: Array[2] } mtproto.js:1452:5
    399 12:27:02.171    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200787684582401", seqno: 1, bytes: 28, body: Object } mtproto.js:1452:5
    400 12:27:02.172    msg-r   <<=m [new_session_created] Object { _: "new_session_created", first_msg_id: "6242200784556418516", unique_id: "13396961033572361155", server_salt: "7076519506215495914" } mtproto.js:1452:5
    401 12:27:02.173    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200787775901697", seqno: 3, bytes: 48, body: Object } mtproto.js:1452:5
    402 12:27:02.174    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200784556418516", result: Object } mtproto.js:1452:5
    407 12:27:02.344    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 25154ms]
    414 12:27:03.068    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200779464550396" } mtproto.js:1452:5
    420 12:27:15.639    CALL    =>> API call auth.sendSms Object { phone_number: "2348022002298", phone_code_hash: "696b5befd8e809de81" } Object { dcID: "4", createNetworker: true, resultType: "auth.SentCode", messageID: "6242200784556418516" } mtproto.js:749:4
    468 12:27:15.924    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 457ms]
    475 12:27:17.154    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200848242727644", result: true } mtproto.js:1452:5
    482 12:27:27.511    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200848242727644" } mtproto.js:1452:5
    505 12:27:31.003    SEND    POST XHR http://149.154.167.51/apiw1 [HTTP/1.1 200 OK 25161ms]
    511 12:27:40.133    CALL    =>> API call auth.signIn Object { phone_number: "2348022002298", phone_code_hash: "696b5befd8e809de81", phone_code: "26914" } Object { dcID: "4", createNetworker: true, resultType: "Bool", messageID: "6242200848242727644" } mtproto.js:749:4
    560 12:27:40.454    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 756ms]
    567 12:27:41.223    msg-r   <<=m [msg_container] Object { _: "msg_container", messages: Array[2] } mtproto.js:1452:5
    568 12:27:41.224    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200956100910081", seqno: 7, bytes: 80, body: Object } mtproto.js:1452:5
    569 12:27:41.225    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200954555850604", result: Object } mtproto.js:1452:5
    570 12:27:41.226    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200956751929345", seqno: 9, bytes: 88, body: Object } mtproto.js:1452:5
    571 12:27:41.227    msg-r   <<=m [updates] Object { _: "updates", updates: Array[1], users: Array[0], chats: Array[0], date: 1453375666, seq: 2 } mtproto.js:1452:5
    579 12:27:41.758    CALL    =>> API call updates.getState Object {  } Object { noErrorBox: true } mtproto.js:749:4
    586 12:27:41.842    CALL    =>> API call account.updateStatus Object { offline: false } Object { noErrorBox: true } mtproto.js:749:4
    594 12:27:41.850    CALL    =>> API call messages.getDialogs Object { offset_date: 0, offset_id: 0, offset_peer: Object, limit: 20 } Object { timeout: 300 } mtproto.js:749:4
    655 12:27:42.965    CALL    =>> API call messages.getAllStickers Object { hash: "" } Object {  } mtproto.js:749:4
    696 12:27:43.920    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 908ms]
    712 12:27:44.613    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 303ms]
    727 12:27:46.488    msg-r   <<=m [msg_container] Object { _: "msg_container", messages: Array[3] } mtproto.js:1452:5
    728 12:27:46.489    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200970862778369", seqno: 11, bytes: 36, body: Object } mtproto.js:1452:5
    729 12:27:46.489    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200960159395644", result: Object } mtproto.js:1452:5
    730 12:27:46.490    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200970891641857", seqno: 13, bytes: 776, body: Object } mtproto.js:1452:5
    731 12:27:46.492    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200960356118244", result: Object } mtproto.js:1452:5
    732 12:27:46.494    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200970897958913", seqno: 15, bytes: 16, body: Object } mtproto.js:1452:5
    733 12:27:46.495    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200960337591900", result: true } mtproto.js:1452:5
    740 12:27:46.567    msg-r   <<=m [msg_container] Object { _: "msg_container", messages: Array[4] } mtproto.js:1452:5
    741 12:27:46.568    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200970862778369", seqno: 11, bytes: 36, body: Object } mtproto.js:1452:5
    742 12:27:46.569    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200960159395644" } mtproto.js:1452:5
    743 12:27:46.569    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200970891641857", seqno: 13, bytes: 776, body: Object } mtproto.js:1452:5
    744 12:27:46.570    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200960356118244" } mtproto.js:1452:5
    745 12:27:46.571    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200970897958913", seqno: 15, bytes: 16, body: Object } mtproto.js:1452:5
    746 12:27:46.572    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200960337591900" } mtproto.js:1452:5
    747 12:27:46.573    msg-r   <<=m [message] Object { _: "message", msg_id: "6242200973791209473", seqno: 17, bytes: 76, body: Object } mtproto.js:1452:5
    748 12:27:46.574    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200964892679524", result: Object } mtproto.js:1452:5
    754 12:27:46.584    CALL    =>> API call messages.getStickerSet Object { stickerset: Object } Object {  } mtproto.js:749:4
    811 12:27:47.346    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 539ms]
    818 12:27:48.175    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242200981275507620", result: Object } mtproto.js:1452:5
    857 12:27:49.351    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 25141ms]
    864 12:27:57.219    msg-r   <<=m [msgs_ack] Object { _: "msgs_ack", msg_ids: Array[0] } mtproto.js:1452:5
    870 12:28:04.673    CALL    =>> API call messages.readHistory Object { peer: Object, max_id: 0 } Object {  } mtproto.js:749:4
    908 12:28:04.860    CALL    =>> API call messages.getHistory Object { peer: Object, offset_id: 16, add_offset: 0, limit: 20 } Object { timeout: 300, noErrorBox: true } mtproto.js:749:4
    922 12:28:05.713    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 367ms]
    929 12:28:06.096    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242201058769372356", result: Object } mtproto.js:1452:5
    936 12:28:15.702    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242201058769372356" } mtproto.js:1452:5
    977 12:28:16.122    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 25170ms]
    983 12:28:26.637    CALL    =>> API call account.updateStatus Object { offline: true } Object { noErrorBox: true } mtproto.js:749:4
    1016    12:28:26.660    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 302ms]
    1023    12:28:27.062    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242201153183272948", result: true } mtproto.js:1452:5
    1030    12:28:41.985    msg-r   <<=m [rpc_result] Object { _: "rpc_result", req_msg_id: "6242201153183272948" } mtproto.js:1452:5
    1071    12:28:42.421    SEND    POST XHR http://149.154.167.91/apiw1 [HTTP/1.1 200 OK 25165ms]
    
    0 讨论(0)
  • 2020-11-22 12:58

    So far I have been able to implement the telegram authorization completely, but not in your requested language - PHP, I used vb.Net. However, I believe the same logic should apply.

    Creating a Telegram Authorization Key

    Telegram API is no walk in the park. Studying existing src code could be quite daunting (IMHO). Hence my approach was to study the online API documentation and implement the sample-auth_key outlined in the links below.

    https://core.telegram.org/mtproto/auth_key

    https://core.telegram.org/mtproto/samples-auth_key

    What this approach will give you is a better understanding and introduction to the primitives used throughout Telegram API, and possibly help you start organizing your own set of functions and routines to handle which you will need for the next steps - implementing other features of the API, since generating an AuthKey is just the beginning.

    Step 1

    All Communication is via TCP - Once you have obtained a unique api_id (https://core.telegram.org/api/obtaining_api_id#obtaining-api-id) you will find the following IP advertised for use in testing: 149.154.167.40:433 The api_id is not required at this point for generating an AuthKey

    Setup your preferred method of Send/Receive TCP processing Loop

    what I have is a private SendData that simply sends a bytes to a live socket connected to the give IP address above

    Private Sub SendData(b() As Byte, Optional read As Boolean = False)
        If Not IsConnected() Then
            Log("Connection Closed!", ConsoleColor.DarkRed)
            RaiseEvent Disconneted()
            Exit Sub
        End If
        
        b = TCPPack(b)
        
        Dim arg = New SocketAsyncEventArgs With {.RemoteEndPoint = ep}
        AddHandler arg.Completed, AddressOf IO_Handler
        arg.SetBuffer(b, 0, b.Length)
        
        Try
            If Not soc.SendAsync(arg) Then
                IO_Handler(soc, arg)
            End If
        
            If read Then
                ReadData()
            End If
        Catch ex As Exception
                Log("SendData: " & ex.ToString, ConsoleColor.Red)
        End Try
    
    End Sub
    
    Private Sub ReadData(Optional wait As Integer = 0)
        If Not IsConnected() Then
            Log("Connection Closed!", ConsoleColor.DarkRed)
            RaiseEvent Disconneted()
            Exit Sub
        End If
    
        Dim arg = New SocketAsyncEventArgs With {.RemoteEndPoint = ep}
        AddHandler arg.Completed, AddressOf IO_Handler
    
        Dim b(BUFFER_SIZE - 1) As Byte
        arg.SetBuffer(b, 0, BUFFER_SIZE)
    
        Try
            If Not soc.ReceiveAsync(arg) Then
                IO_Handler(soc, arg)
            End If
        Catch ex As Exception
            Log("ReadMessages: " & ex.ToString, ConsoleColor.Red)
        End Try
    End Sub
    
    Private Sub IO_Handler(sender As Object, e As SocketAsyncEventArgs)
        Log($"{e.LastOperation}:{e.SocketError}:{e.BytesTransferred}", ConsoleColor.Cyan)
    
        Select Case e.SocketError
            Case SocketError.Success
                Select Case e.LastOperation
                    Case SocketAsyncOperation.Connect 'A socket Connect operation.
                        Log("Connected to " & e.ConnectSocket.RemoteEndPoint.ToString, ConsoleColor.Green)
                        are.Set()
    
                        Case SocketAsyncOperation.Disconnect, SocketAsyncOperation.Connect
                            RaiseEvent Disconneted()
    
                    Case SocketAsyncOperation.Receive 'A socket Receive operation.
                            HandleData(e)
                End Select
    
            Case SocketError.ConnectionAborted
                    RaiseEvent Disconneted()
        End Select
    End Sub
    
    Private Sub HandleData(e As SocketAsyncEventArgs)
        If e.BytesTransferred = 0 Then --no pending data
            Log("The remote end has closed the connection.")
            Exit Sub
        End If
    
        Dim len As Integer = e.Buffer(0)
        Dim start = 1
    
        If len = &H7F Then
            len = e.Buffer(1)
            len += e.Buffer(2) << 8
            len += e.Buffer(3) << 16
            start = 4
        End If
    
        len = 4 * len
    
        Dim data(len - 1) As Byte
        Array.Copy(e.Buffer, start, data, 0, len)
    
    
        ProcessResponse(data)
    
        ReadData()
    End Sub
    

    Finally for this step, we need a TcpPack() method which helps us pad our data in the format Telegram expects - see code below with comments

    Private Function TCPPack(b As Byte()) As Byte()
        Dim a = New List(Of Byte)
        Dim len = CByte(b.Length / 4)
    
        If efSent = False Then --TCP abridged version
            efSent = True
            a.Add(&HEF)
        End If
    
        If len >= &H7F Then
            a.Add(&H7F)
            a.AddRange(BitConverter.GetBytes(len))
        Else
            a.Add(len)
        End If
    
        a.AddRange(b) --only data, no sequence number, no CRC32
    
        Return a.ToArray
    End Function
    

    STEP 2

    With the basic TCP send/receive routines setup, we can start preparing data packets to send to telegram and have sub routines for handling the specific responses received - ProcessResponse(data)

    What we need to understand next is the fact that Telegram handles 2 broad categories of messages -

    Unencrypted - https://core.telegram.org/mtproto/description#unencrypted-message

    These are plain text messages with their auth_key_id =0 generating an AuthKey uses this type of message throughout

    Encrypted - https://core.telegram.org/mtproto/description#encrypted-message-encrypted-data

    All further communication with Telegram Servers will be via encrypted messages

    I choose to have two classes to encapsulate both message types. I can then have two Send(m) methods that handles each type

    Private Sub Send(m As UnencryptedMessage)
        Log(m.ToString, ConsoleColor.DarkYellow, logTime:=False)
        SendData(m.data, True)
    End Sub
    
    Private Sub Send(m As EncryptedMessage)
        Log(m.ToString, ConsoleColor.DarkYellow, logTime:=False)
        SendData(m.data, True)
    End Sub
    

    For now only UnencryptedMessage is required

    Public Class UnencryptedMessage
        Public Property auth_key_id As Int64
        Public Property message_id As Int64
        Public Property data_length As Int32
        Public Property message_data As Byte()
        Public Property message_type As String
        Public Property data As Byte() = {}
        
        Sub New(auth_key As Int64, message_id As Int64, data As Byte())
            _auth_key_id = auth_key
            _message_id = message_id
            _data_length = data.Length
            _message_data = data
            message_type = B2Hr(data, 0, 4)
        
            Dim a = New List(Of Byte)
        
            a.AddRange(BitConverter.GetBytes(auth_key_id)) --{0, 0, 0, 0, 0, 0, 0, 0}
            a.AddRange(BitConverter.GetBytes(message_id))
            a.AddRange(BitConverter.GetBytes(data_length))
            a.AddRange(message_data)
        
            Me.data = a.ToArray
        End Sub
        
        Sub New(b As Byte())
            data = b
        
            Dim skip = 0
        
            _auth_key_id = BitConverter.ToInt64(b, skip) : skip += 8
            _message_id = BitConverter.ToInt64(b, skip) : skip += 8
            _data_length = BitConverter.ToInt32(b, skip) : skip += 4
        
            ReDim _message_data(_data_length - 1)
        
            Array.Copy(b, skip, _message_data, 0, b.Length - skip)
        
            message_type = B2Hr(_message_data, 0, 4)
        End Sub
        
        Public Overrides Function ToString() As String
                Return $"
            raw_data: {B2H(data)}
         auth_key_id: {i2H(auth_key_id)}  {auth_key_id}
          message_id: {i2H(message_id)}  {message_id}
         data_length: {i2H(data_length)}  {data_length}
        message_data: {B2H(message_data)}
        message_type: {message_type}
        "
        End Function
    End Class
    

    STEP 3

    Now we follow he series of steps outlined in https://core.telegram.org/mtproto/auth_key

    • https://core.telegram.org/mtproto/auth_key#dh-exchange-initiation
    1. Client sends query to server

    req_pq#60469778 nonce:int128 = ResPQ The value of nonce is selected randomly by the client (random number) and identifies the client within this communication. Following this step, it is known to all.

    1. Server sends response of the form

    resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector long = ResPQ

    My approach for this is very simple:

    Sub RequestPQAuthorization()
        Send(MTProto.req_pq)
    End Sub
    

    In a Class called MTProto I implement a set of shared functions as required by each step of the exchange. Each method is simply building up an Encrypted data structure which will be sent as above where required

    We start with: req_pq

    Shared Function req_pq(Optional nonce As Byte() = Nothing) As UnencryptedMessage
        --req_pq#60469778 
        --nonce:int128
        If nonce Is Nothing Then
            ReDim nonce(15)
            RND.NextBytes(nonce)
        End If
    
        Dim d = New List(Of Byte)
        d.AddRange({120, 151, 70, 96}) --60469778
        d.AddRange(nonce)
    
        Return New UnencryptedMessage(0, CreateMessageId, d.ToArray)
    End Function
    
    Private Shared Function CreateMessageId() As Int64
        Return CLng((Date.UtcNow.Ticks - ZERO_TICK) * 429.4967296)
    End Function
    

    Public Const ZERO_TICK = 621355968000000000 -- i.e. 1970-01-01T00:00:00Z (January 1, 1970, at 12:00 AM UTC)

    Now our process response method from Step 1

    Private Sub ProcessResponse(data As Byte())
        Try
            Dim r = New UnencryptedMessage(data)
            Log(r.ToString, ConsoleColor.Yellow, logTime:=False)
    
            Select Case r.message_type
                Case resPQ.Classid
                    RequestDHKeyExchange(New resPQ(r.message_data))
                Case server_DH_params_ok.Classid
                    RequestSetDH_params(New server_DH_params_ok(r.message_data), new_nonce)
                Case server_DH_params_fail.Classid
                    Log(New server_DH_params_fail(r.message_data).ToString, ConsoleColor.DarkMagenta)
                Case dh_gen_ok.Classid
                    Log(New dh_gen_ok(r.message_data).ToString, ConsoleColor.Green)
                Case dh_gen_retry.Classid
                    Log(New dh_gen_retry(r.message_data).ToString, ConsoleColor.DarkMagenta)
                Case dh_gen_fail.Classid
                    Log(New dh_gen_fail(r.message_data).ToString, ConsoleColor.DarkMagenta)
                Case Else
                    Log($"Unhandled type: {r.message_type}", ConsoleColor.Magenta)
            End Select
        Catch ex As Exception
            Log($"Error: {ex.ToString}", ConsoleColor.Red)
            Log(B2H(data), ConsoleColor.DarkRed, logTime:=False)
        End Try
    End Sub
    

    Great so far, each response received has a message_type code.

    we can switch on that and determine how each is handled. We need to process resPQ right now.

    What i have done is to create a a set of classes that each handles a specific response type

    ''' <summary>
    ''' resPQ#05162463 
    ''' nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector long = ResPQ
    ''' </summary>
    Public NotInheritable Class resPQ : Inherits TLObject
        Public Shared Shadows ReadOnly Property Classid As String = "05162463"
        Public Property nonce As Byte()
        Public Property server_nonce As Byte()
        Public Property pq As Byte()
        Public Property fingerprints As List(Of UInt64)
        Public Property count As Int32
    
        Sub New(data As Byte())
            Dim skip = 4
            nonce = Slice(data, skip, 16) : skip += 16
            server_nonce = Slice(data, skip, 16) : skip += 16
            skip += 1 'length of pq:string
            pq = Slice(data, skip, 8) : skip += 8
            skip += 3 'padding to complete the 4-bytes
            skip += 4 '%(Vector long) 1cb5c415
            count = i32r(data, skip) : skip += 4
    
            fingerprints = New List(Of UInt64)
    
            For i = 0 To count - 1
                fingerprints.Add(u64r(data, skip))
            Next
        End Sub
    
        Public Overrides Function ToString() As String
            Return $"
         classid: {NameOf(resPQ)}#{Classid}
           nonce: {B2H(nonce)}
    server_nonce: {B2H(server_nonce)}
              pq: {B2H(pq)}  {u64(pq)}
           count: {i2H(count)}  {count}
    fingerprints: {i2H(fingerprints(0))}  {fingerprints(0)}
    "
        End Function
    End Class
    

    Each is based on this simple object

    Public MustInherit Class TLObject
        Public Shared Property ClassId As String
        Public MustOverride Overrides Function ToString() As String
    End Class
    

    Building on this, we tackle steps 3 & 4

    Proof of work 3) Client decomposes pq into prime factors such that p < q.

    This starts a round of Diffie-Hellman key exchanges.

    Presenting proof of work; Server authentication 4) Client sends query to server

    req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params

    This is initiated here RequestDHKeyExchange(New resPQ(r.message_data)) in my ProcessResponse routine above

    Sub RequestDHKeyExchange(r As resPQ)
        Log(r.ToString, ConsoleColor.Gray, logTime:=False)
    
        'decompose prime cofactors
        Dim pp = New PrimeProduct(r.pq)
        Log(pp.ToString, ConsoleColor.Gray, logTime:=False)
    
        'encrypted_data Generation
        Dim pq = New P_Q_inner_data(r.pq, pp.p, pp.q, r.nonce, r.server_nonce)
        new_nonce = pq.new_nonce
    
        'The serialization Of P_Q_inner_data produces some String data. This Is followed by encrypted_data
        'data_with_hash := SHA1(data) + data + (any random bytes); such that the length equal 255 
        Dim data_with_hash = New List(Of Byte)
    
        'SHA1(data) = xxx- 40 =20 bytes
        Using sha1 = New SHA1Managed
            Dim b = pq.ToBytes
            data_with_hash.AddRange(sha1.ComputeHash(b))
            data_with_hash.AddRange(b)
        End Using
    
        If data_with_hash.Count < 255 Then
            Dim pad(255 - data_with_hash.Count - 1) As Byte
            RND.NextBytes(pad)
            data_with_hash.AddRange(pad)
        End If
    
        'RSA(data_with_hash, server_public_key) = xxx - 512 = 256 bytes
        Dim key = i2H(r.fingerprints(0)) 'c3b42b026ce86b21
        Dim zb = Crypto.rsaEncrypt(data_with_hash.ToArray, key)
        Send(MTProto.req_DH_params(r.nonce, r.server_nonce, pp.p, pp.q, r.fingerprints(0), zb))
    End Sub
    

    You can use your own implementation of Prime-Decomposition to replace this line Dim pp = New PrimeProduct(r.pq)

    Here is an example of how I learnt do it using PollardBrent (Pollard Rho Brent Integer Factorization) https://stackoverflow.com/a/31978350/44080

    Okay if you can follow up to this point you have a general idea of how i'm decomposing the AuthKey implementation step by step.

    You should be able to run through the remaining steps 5-9. It's a lot for me to type...

    If this answer so far is of any help to anyone, then i'll take out time to organize and post the remaining part.

    I believe that the routines and knowledge you build up along the way should give you the tools you need to both understand and implement your own independent Telegram API code from scratch.

    Completed Interaction Dump

    03:33:26.591  Connect:Success:0
    03:33:26.593  Connected to 149.154.167.40:443
    03:33:26.598
        raw_data: 000000000000000000DC799836FE075614000000789746604479257F6C01C039A3DEAD031BC2D6A4
     auth_key_id: 0000000000000000  0
      message_id: 5607FE369879DC00  6199202922538589184
     data_length: 00000014  20
    message_data: 789746604479257F6C01C039A3DEAD031BC2D6A4
    message_type: 60469778
    
    03:33:26.600  Send:Success:42
    03:33:26.735  Receive:Success:85
    03:33:26.737
        raw_data: 0000000000000000015CF64539FE075640000000632416054479257F6C01C039A3DEAD031BC2D6A44F9DB065B36308CF4D9965725DD7153D0818DDCAF407B7CDCD00000015C4B51C01000000216BE86C022BB4C3
     auth_key_id: 0000000000000000  0
      message_id: 5607FE3945F65C01  6199202934039141377
     data_length: 00000040  64
    message_data: 632416054479257F6C01C039A3DEAD031BC2D6A44F9DB065B36308CF4D9965725DD7153D0818DDCAF407B7CDCD00000015C4B51C01000000216BE86C022BB4C3
    message_type: 05162463
    
    03:33:26.743
         classid: resPQ#05162463
           nonce: 4479257F6C01C039A3DEAD031BC2D6A4
    server_nonce: 4F9DB065B36308CF4D9965725DD7153D
              pq: 18DDCAF407B7CDCD  1791811376213642701
           count: 00000001  1
    fingerprints: C3B42B026CE86B21  14101943622620965665
    
    03:33:26.810
    PQ: 18DDCAF407B7CDCD  1791811376213642701
     P: 45F57B87  1173715847
     Q: 5AFE490B  1526614283
    
    03:33:26.930
        raw_data: 000000000000000000403CEE36FE075640010000BEE412D74479257F6C01C039A3DEAD031BC2D6A44F9DB065B36308CF4D9965725DD7153D0445F57B87000000045AFE490B000000216BE86C022BB4C3FE0001002DD190DDD93DFFC9EAF14DFAD3018D101E9E3EEC6C3FF4C7C1A067B32FB19AA2FDDFD087094947E793FA9F1A10A36A0B2916609811CFF1F345EE8FD9CDFFBCA4555E33A0446AB4A534500F621D112FCF59CAD4961BC87375F6835460B2E1B3B4088CE79843F7445DC5D87E0ACB0C4A979F68240C06358C4D2F95F86C0535CA643FBE8AF730E70BCBB54191D4F110E50D3244882722605657E808382445FA070A67AED1B2835238C05A00EBE960106838A284BC03D7A01453BA5355F06952F686263DD5B22B66524ED47F843340E9B7FC75BD58B6CC376C0B8B89E7292EDCC08D6CD0F1F9BF8418C2A58BC82B1928B051B3A0C20FA0AB22BA822EFABA6E141508
     auth_key_id: 0000000000000000  0
      message_id: 5607FE36EE3C4000  6199202923977392128
     data_length: 00000140  320
    message_data: BEE412D74479257F6C01C039A3DEAD031BC2D6A44F9DB065B36308CF4D9965725DD7153D0445F57B87000000045AFE490B000000216BE86C022BB4C3FE0001002DD190DDD93DFFC9EAF14DFAD3018D101E9E3EEC6C3FF4C7C1A067B32FB19AA2FDDFD087094947E793FA9F1A10A36A0B2916609811CFF1F345EE8FD9CDFFBCA4555E33A0446AB4A534500F621D112FCF59CAD4961BC87375F6835460B2E1B3B4088CE79843F7445DC5D87E0ACB0C4A979F68240C06358C4D2F95F86C0535CA643FBE8AF730E70BCBB54191D4F110E50D3244882722605657E808382445FA070A67AED1B2835238C05A00EBE960106838A284BC03D7A01453BA5355F06952F686263DD5B22B66524ED47F843340E9B7FC75BD58B6CC376C0B8B89E7292EDCC08D6CD0F1F9BF8418C2A58BC82B1928B051B3A0C20FA0AB22BA822EFABA6E141508
    message_type: D712E4BE
    
    03:33:26.933  Send:Success:341
    03:33:27.217  Receive:Success:656
    03:33:27.217
        raw_data: 0000000000000000011C9A9F39FE0756780200005C07E8D04479257F6C01C039A3DEAD031BC2D6A44F9DB065B36308CF4D9965725DD7153DFE500200752C7BDBB6A58D68B76D2E20DCECF611B2837CA34F3688B242192C633FBBC1EC9348880DA6E6AFF42B256D8476A2C432B60E93218F5B84982B0F9800E6EF918AEC4B729AB1A67C82EF2C4D281352D1BEAEB6B9026CAA0CA8FB03F9257E2CA034471EE25CF6E214BB770E233566A67155BE8FB8F9DA0A76964CFD19E9C97D3E57AAA26E7A6C16B12F2B2BFD4C437857032F0A7198567B9CD3A54BD06CE61A1EBACD70D464185719BC8E0381C99E80A5783D389BE73E97166A328CEDB3AA4D722D453EB4CA893299E41DDC81C798BC76CAF070BFF144F6800D8FE5B3B6BCC9A1138E7ADA6DAF3F581AAB0137A6D40E640E76F6539B1450EA30A55E3F56C2C0A8DCC6F9F4D4F185D25AF37B46B9D9B8ED5CA257DD32EDE02FF95C6174C9D4BA1E30035723C7E2DED9EB0794AAA1913073E4EA2D5649C5C491B252AF88FF1D71EFB5E9FFCA921F0F27F72723DD5014359D08101278DF3F9A9A10DDE54B93A386C6844A6D15AF142DA956A3999458D10BBDE4E947BE949199F088B91175EC9EEE3C95AC47C96D802B0DC91AA6DB5B8A03E0985412DD23CD33FD961175CD271E02BF8A05A537E8FE21CDB40EBAAC0C8D4718DA4499D5B5EF935B848F92C25E9CAE76021758EDD1AA202A0D0DC357348B0474069002EB8F5F2760F2C5BEE38C7CEA07737C28864F647F2406BD55ABD58EEED97A4C8E659143441B1F8CB8DEFE457B46B5E76541CAB63FA1CD3626F0A45DB8A37964BF2613A6C64E6E6E478D44A2AF19CAD6C2686FD55EC85CACD645E58C364CBBD09EF1C7FE7420A8EF277982B87CA18D16B97980B14D24747D9BC86563DA81DA
     auth_key_id: 0000000000000000  0
      message_id: 5607FE399F9A1C01  6199202935543045121
     data_length: 00000278  632
    message_data: 5C07E8D04479257F6C01C039A3DEAD031BC2D6A44F9DB065B36308CF4D9965725DD7153DFE500200752C7BDBB6A58D68B76D2E20DCECF611B2837CA34F3688B242192C633FBBC1EC9348880DA6E6AFF42B256D8476A2C432B60E93218F5B84982B0F9800E6EF918AEC4B729AB1A67C82EF2C4D281352D1BEAEB6B9026CAA0CA8FB03F9257E2CA034471EE25CF6E214BB770E233566A67155BE8FB8F9DA0A76964CFD19E9C97D3E57AAA26E7A6C16B12F2B2BFD4C437857032F0A7198567B9CD3A54BD06CE61A1EBACD70D464185719BC8E0381C99E80A5783D389BE73E97166A328CEDB3AA4D722D453EB4CA893299E41DDC81C798BC76CAF070BFF144F6800D8FE5B3B6BCC9A1138E7ADA6DAF3F581AAB0137A6D40E640E76F6539B1450EA30A55E3F56C2C0A8DCC6F9F4D4F185D25AF37B46B9D9B8ED5CA257DD32EDE02FF95C6174C9D4BA1E30035723C7E2DED9EB0794AAA1913073E4EA2D5649C5C491B252AF88FF1D71EFB5E9FFCA921F0F27F72723DD5014359D08101278DF3F9A9A10DDE54B93A386C6844A6D15AF142DA956A3999458D10BBDE4E947BE949199F088B91175EC9EEE3C95AC47C96D802B0DC91AA6DB5B8A03E0985412DD23CD33FD961175CD271E02BF8A05A537E8FE21CDB40EBAAC0C8D4718DA4499D5B5EF935B848F92C25E9CAE76021758EDD1AA202A0D0DC357348B0474069002EB8F5F2760F2C5BEE38C7CEA07737C28864F647F2406BD55ABD58EEED97A4C8E659143441B1F8CB8DEFE457B46B5E76541CAB63FA1CD3626F0A45DB8A37964BF2613A6C64E6E6E478D44A2AF19CAD6C2686FD55EC85CACD645E58C364CBBD09EF1C7FE7420A8EF277982B87CA18D16B97980B14D24747D9BC86563DA81DA
    message_type: D0E8075C
    
    03:33:27.240
         classid: server_DH_params_ok#D0E8075C
           nonce: 4479257F6C01C039A3DEAD031BC2D6A4
    server_nonce: 4F9DB065B36308CF4D9965725DD7153D
      enc_answer: 752C7BDBB6A58D68B76D2E20DCECF611B2837CA34F3688B242192C633FBBC1EC9348880DA6E6AFF42B256D8476A2C432B60E93218F5B84982B0F9800E6EF918AEC4B729AB1A67C82EF2C4D281352D1BEAEB6B9026CAA0CA8FB03F9257E2CA034471EE25CF6E214BB770E233566A67155BE8FB8F9DA0A76964CFD19E9C97D3E57AAA26E7A6C16B12F2B2BFD4C437857032F0A7198567B9CD3A54BD06CE61A1EBACD70D464185719BC8E0381C99E80A5783D389BE73E97166A328CEDB3AA4D722D453EB4CA893299E41DDC81C798BC76CAF070BFF144F6800D8FE5B3B6BCC9A1138E7ADA6DAF3F581AAB0137A6D40E640E76F6539B1450EA30A55E3F56C2C0A8DCC6F9F4D4F185D25AF37B46B9D9B8ED5CA257DD32EDE02FF95C6174C9D4BA1E30035723C7E2DED9EB0794AAA1913073E4EA2D5649C5C491B252AF88FF1D71EFB5E9FFCA921F0F27F72723DD5014359D08101278DF3F9A9A10DDE54B93A386C6844A6D15AF142DA956A3999458D10BBDE4E947BE949199F088B91175EC9EEE3C95AC47C96D802B0DC91AA6DB5B8A03E0985412DD23CD33FD961175CD271E02BF8A05A537E8FE21CDB40EBAAC0C8D4718DA4499D5B5EF935B848F92C25E9CAE76021758EDD1AA202A0D0DC357348B0474069002EB8F5F2760F2C5BEE38C7CEA07737C28864F647F2406BD55ABD58EEED97A4C8E659143441B1F8CB8DEFE457B46B5E76541CAB63FA1CD3626F0A45DB8A37964BF2613A6C64E6E6E478D44A2AF19CAD6C2686FD55EC85CACD645E58C364CBBD09EF1C7FE7420A8EF277982B87CA18D16B97980B14D24747D9BC86563DA81DA
    
    tmp_aes_key: 297CB750FF0052B67515B3F11B45F11F15D106BC25ED0027570D5B9D83102BFA
     tmp_aes_iv: CBDCF40A77B6A1C7CE74A1F8EC8E091A49FAD3B9A2499BFFFD084D537A53B36D
         answer: BA0D89B54479257F6C01C039A3DEAD031BC2D6A44F9DB065B36308CF4D9965725DD7153D03000000FE000100C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C3720FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F642477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5BFE000100C49E858CA0107FF9B51DC88236370866BE4A69DDC2193930769C11722D2884CE5017AF60712B6BAC17F79DBA8701A25AAA901FDCB483C56A246C1CA7705FAA87F0AFD68EAC8FC5EC88307298DAF7252DD6D8630BF819D65F9E4B5624B6A05149B35B8509A63C2F2D05417F38DD0A90727F5D12CC4D213B5974C732FB261F6AC01426F2B7269C17230442AA8C9AFCCD927463C4EC8465F841D969F0C47FC270D8EC23B1F5D861EB6A5602CF6F87A02A56A4094E06509503CACE935461086668AC32E8C69A90EB19C3232B20635DFADFC6E4EDC11FA34A3E2E2BBA28DDCEF422120077D3A171A6A5B65744113AF0D0A1FC566D31DBBDB43F5DE35A7CE5F0BB0ECD39FE0756646CF781176C3EAC
    
         classid: Server_DH_inner_data#B5890DBA
           nonce: 4479257F6C01C039A3DEAD031BC2D6A4
    server_nonce: 4F9DB065B36308CF4D9965725DD7153D
               g: 00000003  3
        dh_prime: C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C3720FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F642477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5B
             g_a: C49E858CA0107FF9B51DC88236370866BE4A69DDC2193930769C11722D2884CE5017AF60712B6BAC17F79DBA8701A25AAA901FDCB483C56A246C1CA7705FAA87F0AFD68EAC8FC5EC88307298DAF7252DD6D8630BF819D65F9E4B5624B6A05149B35B8509A63C2F2D05417F38DD0A90727F5D12CC4D213B5974C732FB261F6AC01426F2B7269C17230442AA8C9AFCCD927463C4EC8465F841D969F0C47FC270D8EC23B1F5D861EB6A5602CF6F87A02A56A4094E06509503CACE935461086668AC32E8C69A90EB19C3232B20635DFADFC6E4EDC11FA34A3E2E2BBA28DDCEF422120077D3A171A6A5B65744113AF0D0A1FC566D31DBBDB43F5DE35A7CE5F0BB0ECD
     server_time: 5607FE39  1443364409
     client_time: 5607FE37  1443364407
         padding: 646CF781176C3EAC
    
    DH_Prime is Safe? = True
    
         classid: Client_DH_Inner_Data#6643B654
           nonce: 4479257F6C01C039A3DEAD031BC2D6A4
    server_nonce: 4F9DB065B36308CF4D9965725DD7153D
        retry_id: 0000000000000000  0
             g_b: 923A21384FE0318D569B2F2BEA667D1A999050A0A1B5AFDA39F2B890DEE45F9ED08E319C8243CD1496269CCF956DFA6C98633BDC2E26B1675C15D7904417EC2A74C687E682ED14182178BC0BD189F6E020131C87FD42A24798FCCD2416348EE0AAF534B652175BAC33E89C82874A8C3E8562815DDA213610167B10153EFC1BD1A0CFBACFEA22E3E8D80917F262D2C67BF1327A245CF7FE0E299F7517EE6A2F65568630A6191FEB0C1254F260A6554ED2BEE19E94AAB693E58DD032C26B9CAFEB0482F12DE2573B6E6D2816AC37ADDF3B99525FDBAF94690926320CC67ABF35D3EA6EC6CC7211BAF11FBDD6897959F6F1E3D4335B89B3024C1B3C0066246B5DCD
    
    03:33:27.590  enc_data: 0A974C499344B093ADF321597858B1A6179E2A6C21F5FF9EB5DE687CDB57F8059509482FF9846FBE99D9411C13A645B26F73960424A13337D87DA879864FCA9D0883B643CF8EB594446038E0B6C4FD606D0CB77F1E00CCA6291DD65733F6A60217C7F366AD88972F107C381FD375F49DB57A2AB96988EC916629CD6F58B53F65DF4909AA773CCA43CE43671CA313528190213CF28A3B29BE26865BE22EB0C41E89CBD698C96CBC1B7B7F1586FBD61B422693859843F7D32083E3AB23D607FC4B874DB849F430F74483969ABA4603B483C94BCEB38F8EC90EEB58B338B325A8E37B57813CEC7E795B1B5517D732227856955C53BA18F52E55C6BCD8F1419D43D46DF2C2560B74BA7AA961BB4BDD09ABBC95E4F57AC4B8C89A67C7C5453A3EFB635D3977E0C3F0067C1F4D255F1F87E74A8E7E4272DFDEB9B85ABBEFA4953B2E0ECAA15C3C77773155C4013955BAB0D85F
    03:33:27.810  auth_Key: 87A801A14AD6426E6AD56B638B315DF9F5B66F77333DC8C0FAADB77A1D51E71B68F5BB9B21DB275F2C4CA495E6440DDEACBDB199C52C327F7E2E9D78921E0D632CCA63DB6384FAF387E9D41717899EE5D54609C2F88573BBE8128FB5864CB62BC7F0ED250CBB57929AA5198FE568FC76FB846262A505B42D04BCB87C9EB24007CE9F9BDEB79391E7E9425F3A3D5028410E129C078EB8644EAB770F8705D8228CFAEAA4478A0D8E326971C7C2223074C4302C1F1DE5D08AC00CBEBEE41981B57A4248B517386DE68A51D01087F0E58D75A4C0FD2D031BC5BFC08651C4133494B572150EDD1C486153E8F51F99771DD57F55B3A5BBAE1874F25E69150C4E3C1397
    03:33:27.813
        raw_data: 0000000000000000009C48D037FE0756780100001F5F04F54479257F6C01C039A3DEAD031BC2D6A44F9DB065B36308CF4D9965725DD7153DFE5001000A974C499344B093ADF321597858B1A6179E2A6C21F5FF9EB5DE687CDB57F8059509482FF9846FBE99D9411C13A645B26F73960424A13337D87DA879864FCA9D0883B643CF8EB594446038E0B6C4FD606D0CB77F1E00CCA6291DD65733F6A60217C7F366AD88972F107C381FD375F49DB57A2AB96988EC916629CD6F58B53F65DF4909AA773CCA43CE43671CA313528190213CF28A3B29BE26865BE22EB0C41E89CBD698C96CBC1B7B7F1586FBD61B422693859843F7D32083E3AB23D607FC4B874DB849F430F74483969ABA4603B483C94BCEB38F8EC90EEB58B338B325A8E37B57813CEC7E795B1B5517D732227856955C53BA18F52E55C6BCD8F1419D43D46DF2C2560B74BA7AA961BB4BDD09ABBC95E4F57AC4B8C89A67C7C5453A3EFB635D3977E0C3F0067C1F4D255F1F87E74A8E7E4272DFDEB9B85ABBEFA4953B2E0ECAA15C3C77773155C4013955BAB0D85F
     auth_key_id: 0000000000000000  0
      message_id: 5607FE37D0489C00  6199202927769852928
     data_length: 00000178  376
    message_data: 1F5F04F54479257F6C01C039A3DEAD031BC2D6A44F9DB065B36308CF4D9965725DD7153DFE5001000A974C499344B093ADF321597858B1A6179E2A6C21F5FF9EB5DE687CDB57F8059509482FF9846FBE99D9411C13A645B26F73960424A13337D87DA879864FCA9D0883B643CF8EB594446038E0B6C4FD606D0CB77F1E00CCA6291DD65733F6A60217C7F366AD88972F107C381FD375F49DB57A2AB96988EC916629CD6F58B53F65DF4909AA773CCA43CE43671CA313528190213CF28A3B29BE26865BE22EB0C41E89CBD698C96CBC1B7B7F1586FBD61B422693859843F7D32083E3AB23D607FC4B874DB849F430F74483969ABA4603B483C94BCEB38F8EC90EEB58B338B325A8E37B57813CEC7E795B1B5517D732227856955C53BA18F52E55C6BCD8F1419D43D46DF2C2560B74BA7AA961BB4BDD09ABBC95E4F57AC4B8C89A67C7C5453A3EFB635D3977E0C3F0067C1F4D255F1F87E74A8E7E4272DFDEB9B85ABBEFA4953B2E0ECAA15C3C77773155C4013955BAB0D85F
    message_type: F5045F1F
    
    03:33:27.823  Send:Success:397
    03:33:27.983  Receive:Success:73
    03:33:27.985
    

    ....

    Regards.

    0 讨论(0)
  • 2020-11-22 13:04

    As of February'2018 you can use an official Telegram Login Widget on your website.

    0 讨论(0)
  • 2020-11-22 13:09

    I have written a PHP implementation of mtproto, and so far I have managed to implement TL serialization/deserialization, tcp abridged/intermediate/full connections, http/https connections.

    I have implemented OOP wrappers for all mtproto methods, a prime generation module based on Python/wolfram alpha/php, HTML/Markdown parsing with support for mentions, bot API file id support, update handling with callbacks or getupdates, bot API <-> MTProto object conversion, upload/download wrappers, login wrappers for bots/users (2FA is supported), simple error handling, internal peer management (you can provide a simple bot API chat id, a username or a peer id in tg-cli format to send a message or to call other mtproto methods) and I am currently working on a nice Lua wrapper to allow usage of td-cli/tg-cli bots w/ MadelineProto.

    I have also written a class to generate documentation for all mtproto methods/constructors/types (available at https://daniil.it/MadelineProto/API_docs). MadelineProto can be serialized to a file to allow easy session storage.

    If anyone is interested, or wants to contribute, here is the link to the github repo: https://github.com/danog/MadelineProto

    0 讨论(0)
提交回复
热议问题