Asked  7 Months ago    Answers:  5   Viewed   28 times

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 users (all of them have a carma like here (+10, -2, +1000 etc.) with relevant group taxonomy: web-masters and customers) have a user profile on my website. After they reach a certain amount of carma and since they are authorized in their profile they are joined to private chats based on Telegram generated for them automatically.

After some research, I found that it's very complicated because:

  1. I've never had an experience of API implementation for hardware-binded social networks.
  2. I took a look at https://core.telegram.org/api/auth, but it's completely unobvious how to implement these functions (for example auth.sendCode), using PHP or any other language. If these commands should be sent as JSON to server, then it doesn't look like JSON:

      auth.sentCode#efed51d9 phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode;
    

    What is it? In which language is it written?

    UPD: It's written in TL (Type Language): https://core.telegram.org/mtproto/TL

  3. I've explored the source code of several clients (Webogram, Telegram-cli (tg), tdesktop), and I found several implementations of https://core.telegram.org/mtproto

Unfortunately, none of them support multiple authorization on their side, and after a little bit of research, I have no idea where to dig deeper to find out more information.

Also, these implementations look bulky and compound (for example, https://github.com/vysheng/tg): enter image description here

There I see bunch of servers (./tg/tgl/tgl.h):

#define TG_SERVER_1 "149.154.175.50"
#define TG_SERVER_2 "149.154.167.51"
#define TG_SERVER_3 "149.154.175.100"
#define TG_SERVER_4 "149.154.167.91"
#define TG_SERVER_5 "149.154.171.5"

I found several possibly appropriate functions (./tg/tgl/queries.c):

void empty_auth_file (void) {
  if (TLS->test_mode) {
    bl_do_dc_option (TLS, 1, "", 0, TG_SERVER_TEST_1, strlen (TG_SERVER_TEST_1), 443);
    bl_do_dc_option (TLS, 2, "", 0, TG_SERVER_TEST_2, strlen (TG_SERVER_TEST_2), 443);
    bl_do_dc_option (TLS, 3, "", 0, TG_SERVER_TEST_3, strlen (TG_SERVER_TEST_3), 443);
    bl_do_set_working_dc (TLS, TG_SERVER_TEST_DEFAULT);
  } else {
    bl_do_dc_option (TLS, 1, "", 0, TG_SERVER_1, strlen (TG_SERVER_1), 443);
    bl_do_dc_option (TLS, 2, "", 0, TG_SERVER_2, strlen (TG_SERVER_2), 443);
    bl_do_dc_option (TLS, 3, "", 0, TG_SERVER_3, strlen (TG_SERVER_3), 443);
    bl_do_dc_option (TLS, 4, "", 0, TG_SERVER_4, strlen (TG_SERVER_4), 443);
    bl_do_dc_option (TLS, 5, "", 0, TG_SERVER_5, strlen (TG_SERVER_5), 443);
    bl_do_set_working_dc (TLS, TG_SERVER_DEFAULT);
  }
}

void bl_do_dc_option (struct tgl_state *TLS, int id, const char *name, int l1, const char *ip, int l2, int port) {
  struct tgl_dc *DC = TLS->DC_list[id];
  if (DC && !strncmp (ip, DC->ip, l2)) { return; }

  clear_packet ();
  out_int (CODE_binlog_dc_option);
  out_int (id);
  out_cstring (name, l1);
  out_cstring (ip, l2);
  out_int (port);

  add_log_event (TLS, packet_buffer, 4 * (packet_ptr - packet_buffer));
}

etc.

What files should I transfer to PHP for multiple user auth implementation? Could you please help me to know where to start from and how to make it easier than it currently is?

Thank you in advance!

 Answers

91

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.

Wednesday, March 31, 2021
 
buymypies
answered 7 Months ago
16

POST, PUT, GET are all HTTP verbs and do not, in and of themselves, indicate a format for transferring the data, so there is no POST format. That means that you can encode the data in any way you choose.

Now, what format you decide to go with should really be more a matter of how your API will generally be used. If it will be primarily fielding form submits from a web browser, then using a form fields encoding is likely the most reasonable thing to do since it makes that interaction easier for the client.

On the other hand, if you are primarily going to be receiving JSON data from AJAX calls, then receiving a JSON format may make sense. If you will do both, there isn't any reason you can't accept data in both formats.

The other aspect to consider is the complexity of the data structures you will be passing back and forth. Form encoding (similar to query-string encoding as well) is a key-value structure, while JSON (or XML) allows for a much richer data structure.

In the end, go with whatever is simplest for both you on the server side, as well as you on the client side (since I assume you will also be writing the primary client consumer of the API in question). Simplicity is always preferred over complexity until you can definitively show that more complexity gives you a measurable benefit.

Also, the last thing I will mention is that REST isn't just about clean URLs or using HTTP verbs correctly. Those aspects are really just icing on the cake. The core idea behind a REST architecture is that Hypertext is the engine of application state. By simply following URLs in the server responses, a good client can learn about all of the available actions and doesn't need to know anything more than the base URL. Everything else can be discovered from that. Couple that with well defined content types and you have a world where lots of clients can communicate with lots of servers, all speaking the same "language", and the clients don't need to know anything about the servers (or vice-versa) other than the base URL and the content types. That's what REST is all about.

Wednesday, March 31, 2021
 
rob_mccann
answered 7 Months ago
29

you have to enable apache mod_rewrite

Saturday, May 29, 2021
 
Zulakis
answered 5 Months ago
20

For internet services to stay alive, they need to fight with any type of spam. As the result, Telegram bots can't start sending messages to users that didn't start using the bot yet!

Only when a user starts using the bot you can see his/hers chat_id and send messages to him.

That being said, if a user (User A) sends you a contact details of another user (Let's call this one, User B), you can see user_id of the user B. However you still can't send any messages directly, unless he/she also started using the bot before.

This behavior allows us to make a workaround and query users by phone number or at least confirm a user's phone number if required.

To do so, first, you need to create contact message. It doesn't matter who sents the message, even the bot can send the message. The idea is to let Telegram fill the user_id of the new contact message. You can read about this object here: Contact Object

The method we need to use is sendContact and it needs a target chat_id, a first_name and a phone_number. Now first_name can be any string and its value is irrelevant to the process. Also, chat_id can be the identification of any user's chat with the bot, even yours. It can also be the name of a group or a channel in which the bot is an administrator with write access, for example, @my_private_bot_channel. In short, anywhere that bot can post a message. So you only need to provide the phone_number.

After sending the message, you will get a server response, along with the Message that your bot just posted. The contact field of this newly created message contains information about the user you just shared his contact, possibly along with his/hers telegram user_id which is the same thing as the user's chat id.

Right afterward you can delete your message with the deleteMessage method.

Following is an example of doing so in plain request/response format, but you should probably use a framework for this:

https://api.telegram.org/{BOT_TOKEN}/sendContact?chat_id=123456789&phone_number=+989123456789&first_name=Some+Random+String

The response to this request is as follow:

{
    "ok": true,
    "result": {
        "message_id": 12345678987654321,
        "from": {
            "id": 987654321,
            "first_name": "The Bot Name",
            "username": "mybot_bot"
        },
        "chat": {
            "id": 123456789,
            "first_name": "Your Chat Party",
            "last_name": "Your Chat Party",
            "type": "private"
        },
        "date": 1484612850,
        "contact": {
            "phone_number": "989123456789",
            "first_name": "Some Random String",
            "user_id": 654789321
        }
    }
}

"user_id": 654789321 is the part that we are interested in. Now you can delete your message.

Monday, August 2, 2021
 
TecHunter
answered 3 Months ago
30

Yes you can....

Specify Destination Type as FILE_URI itself and in imagedata you will be getting the images file uri place it in a image tag and then place it inside HTML5 canvas and canvas has one method called toDataURL where you will be able to get the base64 of the corresponding image.

function onSuccess(imageData)
     {

                var $img = $('<img/>');
                $img.attr('src', imageData);
                $img.css({position: 'absolute', left: '0px', top: '-999999em', maxWidth: 'none', width: 'auto', height: 'auto'});
                $img.bind('load', function() 
                {
                    var canvas = document.createElement("canvas");
                    canvas.width = $img.width();
                    canvas.height = $img.height();
                    var ctx = canvas.getContext('2d');
                    ctx.drawImage($img[0], 0, 0);
                    var dataUri = canvas.toDataURL('image/png');

                });
                $img.bind('error', function() 
                {
                    console.log('Couldnt convert photo to data URI');
                });

    }
Friday, August 13, 2021
 
scessor
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :