mtproto 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mtproto/auth_key_generator.rb +16 -6
  3. data/lib/mtproto/client/rpc.rb +141 -0
  4. data/lib/mtproto/client.rb +36 -181
  5. data/lib/mtproto/crypto/aes_ige.rb +1 -1
  6. data/lib/mtproto/crypto/factorization.rb +1 -1
  7. data/lib/mtproto/message_id.rb +13 -0
  8. data/lib/mtproto/rpc/get_config.rb +37 -0
  9. data/lib/mtproto/rpc/get_contacts.rb +22 -0
  10. data/lib/mtproto/rpc/get_updates_difference.rb +33 -0
  11. data/lib/mtproto/rpc/get_updates_state.rb +22 -0
  12. data/lib/mtproto/rpc/get_users.rb +22 -0
  13. data/lib/mtproto/rpc/ping.rb +26 -0
  14. data/lib/mtproto/rpc/send_code.rb +44 -0
  15. data/lib/mtproto/rpc/send_message.rb +31 -0
  16. data/lib/mtproto/rpc/sign_in.rb +52 -0
  17. data/lib/mtproto/tl/auth_key/dh_gen_response.rb +37 -0
  18. data/lib/mtproto/tl/auth_key/req_dh_params.rb +31 -0
  19. data/lib/mtproto/tl/auth_key/req_pq_multi.rb +18 -0
  20. data/lib/mtproto/tl/auth_key/res_pq.rb +62 -0
  21. data/lib/mtproto/tl/auth_key/server_dh_params.rb +43 -0
  22. data/lib/mtproto/tl/auth_key/set_client_dh_params.rb +25 -0
  23. data/lib/mtproto/tl/message.rb +2 -216
  24. data/lib/mtproto/tl/method_builder.rb +29 -0
  25. data/lib/mtproto/tl/rpc/auth/authorization.rb +107 -0
  26. data/lib/mtproto/tl/rpc/auth/send_code.rb +28 -0
  27. data/lib/mtproto/tl/rpc/auth/sent_code.rb +36 -0
  28. data/lib/mtproto/tl/rpc/auth/sign_in.rb +32 -0
  29. data/lib/mtproto/tl/rpc/contacts/contacts.rb +155 -0
  30. data/lib/mtproto/tl/rpc/contacts/get_contacts.rb +18 -0
  31. data/lib/mtproto/tl/rpc/help/config.rb +35 -0
  32. data/lib/mtproto/tl/rpc/help/get_config.rb +17 -0
  33. data/lib/mtproto/tl/rpc/messages/send_message.rb +43 -0
  34. data/lib/mtproto/tl/rpc/messages/updates.rb +87 -0
  35. data/lib/mtproto/tl/rpc/ping.rb +18 -0
  36. data/lib/mtproto/tl/rpc/pong.rb +46 -0
  37. data/lib/mtproto/tl/rpc/updates/difference.rb +332 -0
  38. data/lib/mtproto/tl/rpc/updates/get_difference.rb +42 -0
  39. data/lib/mtproto/tl/rpc/updates/get_state.rb +17 -0
  40. data/lib/mtproto/tl/rpc/updates/state.rb +59 -0
  41. data/lib/mtproto/tl/rpc/users/get_users.rb +25 -0
  42. data/lib/mtproto/tl/rpc/users/users.rb +99 -0
  43. data/lib/mtproto/updates_poller.rb +111 -0
  44. data/lib/mtproto/version.rb +1 -1
  45. data/lib/mtproto.rb +10 -1
  46. metadata +53 -5
  47. data/ext/aes_ige/Makefile +0 -273
  48. data/ext/factorization/Makefile +0 -273
  49. data/lib/mtproto/connection.rb +0 -103
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e7f507f0d6cf42ac479bf224933efca12e7519cd67d7e9d8796ceba14f517960
4
- data.tar.gz: 79c5137adfc60752fecb5367c6b90a08e7648f8fc523a95382fe7e755888c439
3
+ metadata.gz: 2744b720c59f90c3e9d18021ce6096a1c8e559dae949fbd6a9b53948c14f8b5c
4
+ data.tar.gz: 3b9000cabc247db305244b279bc58474466e1549cca3efa07ca1202eaa2d7874
5
5
  SHA512:
6
- metadata.gz: 48de4193ba146630f831f690527cefcc0577c1bf56ab32452092e68dd75fa5bf86b294b8578e88e4daa26766c39ef78aa60c1a132e38975d6b01f0c21c508f29
7
- data.tar.gz: 46d2ad65c9c1f59ea5f75789fb27008620117ab63877dad711add23cb6d477ad9cea5e5dffb724cc4d1d128a67dd9b75f8db9eddaf8e30a16005c377cb1a7542
6
+ metadata.gz: 874a17be8f75bb305057d0a0cb2c136441f9e8da883c44a99169ad0975c5b745b4323abc84ab6edb96b72f2c8f500ec40536a1a6724f585730501514a2e7475b
7
+ data.tar.gz: 6a693436a7443f789cb73a6fe6ecebf523ee288bb174b297fdfac4274340c9a5a00544299d08f0558028645e4cf80dbfb0c70c844ec47d2bb6e413589a45a5b2
@@ -2,6 +2,13 @@
2
2
 
3
3
  require 'securerandom'
4
4
  require 'digest'
5
+ require_relative 'message_id'
6
+ require_relative 'tl/auth_key/req_pq_multi'
7
+ require_relative 'tl/auth_key/res_pq'
8
+ require_relative 'tl/auth_key/req_dh_params'
9
+ require_relative 'tl/auth_key/server_dh_params'
10
+ require_relative 'tl/auth_key/set_client_dh_params'
11
+ require_relative 'tl/auth_key/dh_gen_response'
5
12
 
6
13
  module MTProto
7
14
  class AuthKeyGenerator
@@ -80,12 +87,13 @@ module MTProto
80
87
 
81
88
  def req_pq_multi
82
89
  nonce = SecureRandom.random_bytes(16)
83
- message = TL::Message.req_pq_multi(nonce)
90
+ body = TL::AuthKey::ReqPqMulti.build(nonce)
91
+ message = TL::Message.new(auth_key_id: 0, msg_id: MessageId.generate, body: body)
84
92
  @connection.send(message.serialize)
85
93
 
86
94
  response_data = @connection.recv(timeout: @timeout)
87
95
  response_message = TL::Message.deserialize(response_data)
88
- res_pq = response_message.parse_res_pq
96
+ res_pq = TL::AuthKey::ResPq.parse(response_message.body)
89
97
 
90
98
  raise 'Nonce mismatch!' unless res_pq[:nonce] == nonce
91
99
 
@@ -120,7 +128,7 @@ module MTProto
120
128
  end
121
129
 
122
130
  def send_req_dh_params(res_pq, p, q, server_key, encrypted_data)
123
- message = TL::Message.req_DH_params(
131
+ body = TL::AuthKey::ReqDHParams.build(
124
132
  nonce: res_pq[:nonce],
125
133
  server_nonce: res_pq[:server_nonce],
126
134
  p: p,
@@ -128,12 +136,13 @@ module MTProto
128
136
  public_key_fingerprint: server_key.fingerprint,
129
137
  encrypted_data: encrypted_data
130
138
  )
139
+ message = TL::Message.new(auth_key_id: 0, msg_id: MessageId.generate, body: body)
131
140
 
132
141
  @connection.send(message.serialize)
133
142
 
134
143
  response_data = @connection.recv(timeout: @timeout)
135
144
  response_message = TL::Message.deserialize(response_data)
136
- server_dh_params = response_message.parse_server_DH_params_ok
145
+ server_dh_params = TL::AuthKey::ServerDHParams.parse(response_message.body)
137
146
 
138
147
  raise 'Nonce mismatch!' unless server_dh_params[:nonce] == res_pq[:nonce]
139
148
  raise 'Server nonce mismatch!' unless server_dh_params[:server_nonce] == res_pq[:server_nonce]
@@ -191,17 +200,18 @@ module MTProto
191
200
  tmp_aes_iv
192
201
  )
193
202
 
194
- message = TL::Message.set_client_DH_params(
203
+ body = TL::AuthKey::SetClientDHParams.build(
195
204
  nonce: res_pq[:nonce],
196
205
  server_nonce: res_pq[:server_nonce],
197
206
  encrypted_data: client_dh_encrypted
198
207
  )
208
+ message = TL::Message.new(auth_key_id: 0, msg_id: MessageId.generate, body: body)
199
209
 
200
210
  @connection.send(message.serialize)
201
211
 
202
212
  response_data = @connection.recv(timeout: @timeout)
203
213
  response_message = TL::Message.deserialize(response_data)
204
- response_message.parse_dh_gen_response
214
+ TL::AuthKey::DHGenResponse.parse(response_message.body)
205
215
  end
206
216
 
207
217
  def verify_dh_gen_response(dh_gen_response, res_pq, new_nonce, auth_key)
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../message_id'
4
+
5
+ module MTProto
6
+ class Client
7
+ class RPC
8
+ CONSTRUCTOR_RPC_RESULT = 0xf35c6d01
9
+ CONSTRUCTOR_MSGS_ACK = 0x62d6b459
10
+ CONSTRUCTOR_BAD_SERVER_SALT = 0xedab447b
11
+
12
+ def initialize(client)
13
+ @client = client
14
+ @connection_initialized = false
15
+ end
16
+
17
+ def call(body, content_related: true)
18
+ raise 'Auth key not generated' unless @client.auth_key
19
+ raise 'Session not initialized' unless @client.session
20
+
21
+ msg_id = MessageId.generate(time_offset: @client.time_offset)
22
+ seq_no = @client.session.next_seq_no(content_related: content_related)
23
+
24
+ encrypted_msg = EncryptedMessage.encrypt(
25
+ auth_key: @client.auth_key,
26
+ server_salt: @client.server_salt,
27
+ session_id: @client.session.session_id,
28
+ msg_id: msg_id,
29
+ seq_no: seq_no,
30
+ body: body
31
+ )
32
+
33
+ @client.connection.send(encrypted_msg.serialize)
34
+
35
+ response_data = @client.connection.recv(timeout: @client.timeout)
36
+
37
+ decrypted = EncryptedMessage.decrypt(
38
+ auth_key: @client.auth_key,
39
+ encrypted_message_data: response_data,
40
+ sender: :server
41
+ )
42
+
43
+ response_body = decrypted[:body]
44
+
45
+ constructor = response_body[0, 4].unpack1('L<')
46
+
47
+ # Handle bad_server_salt
48
+ if constructor == CONSTRUCTOR_BAD_SERVER_SALT
49
+ # bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long
50
+ offset = 4
51
+ bad_msg_id = response_body[offset, 8].unpack1('Q<')
52
+ offset += 8
53
+ bad_msg_seqno = response_body[offset, 4].unpack1('L<')
54
+ offset += 4
55
+ error_code = response_body[offset, 4].unpack1('L<')
56
+ offset += 4
57
+ new_server_salt = response_body[offset, 8].unpack1('Q<')
58
+
59
+ # Update server salt and retry
60
+ update_server_salt(new_server_salt)
61
+ return call(body, content_related: content_related)
62
+ end
63
+
64
+ if constructor == TL::NewSessionCreated::CONSTRUCTOR
65
+ session_info = TL::NewSessionCreated.deserialize(response_body)
66
+ update_server_salt(session_info.server_salt)
67
+
68
+ response_data = @client.connection.recv(timeout: @client.timeout)
69
+ decrypted = EncryptedMessage.decrypt(
70
+ auth_key: @client.auth_key,
71
+ encrypted_message_data: response_data,
72
+ sender: :server
73
+ )
74
+ response_body = decrypted[:body]
75
+ constructor = response_body[0, 4].unpack1('L<')
76
+ end
77
+
78
+ if constructor == TL::MsgContainer::CONSTRUCTOR
79
+ container = TL::MsgContainer.deserialize(response_body)
80
+
81
+ rpc_result = container.messages.find do |msg|
82
+ msg[:body][0, 4].unpack1('L<') == CONSTRUCTOR_RPC_RESULT
83
+ end
84
+
85
+ return rpc_result[:body][12..] if rpc_result
86
+
87
+ new_session = container.messages.find do |msg|
88
+ msg[:body][0, 4].unpack1('L<') == TL::NewSessionCreated::CONSTRUCTOR
89
+ end
90
+ if new_session
91
+ session_info = TL::NewSessionCreated.deserialize(new_session[:body])
92
+ update_server_salt(session_info.server_salt)
93
+
94
+ other_messages = container.messages.reject do |msg|
95
+ constructor = msg[:body][0, 4].unpack1('L<')
96
+ (
97
+ constructor == TL::NewSessionCreated::CONSTRUCTOR ||
98
+ constructor == CONSTRUCTOR_MSGS_ACK
99
+ )
100
+ end
101
+
102
+ return other_messages.first[:body] unless other_messages.empty?
103
+
104
+ response_data = @client.connection.recv(timeout: @client.timeout)
105
+ decrypted = EncryptedMessage.decrypt(
106
+ auth_key: @client.auth_key,
107
+ encrypted_message_data: response_data,
108
+ sender: :server
109
+ )
110
+ response_body = decrypted[:body]
111
+ constructor = response_body[0, 4].unpack1('L<')
112
+
113
+ return response_body[12..] if constructor == CONSTRUCTOR_RPC_RESULT
114
+
115
+ if constructor == TL::MsgContainer::CONSTRUCTOR
116
+ container = TL::MsgContainer.deserialize(response_body)
117
+ rpc_result = container.messages.find do |msg|
118
+ msg[:body][0, 4].unpack1('L<') == CONSTRUCTOR_RPC_RESULT
119
+ end
120
+ return rpc_result[:body][12..] if rpc_result
121
+ end
122
+
123
+ return response_body
124
+ end
125
+
126
+ return container.messages.first[:body]
127
+ end
128
+
129
+ return response_body[12..] if constructor == CONSTRUCTOR_RPC_RESULT
130
+
131
+ response_body
132
+ end
133
+
134
+ private
135
+
136
+ def update_server_salt(server_salt)
137
+ @client.instance_variable_set(:@server_salt, server_salt)
138
+ end
139
+ end
140
+ end
141
+ end
@@ -2,16 +2,19 @@
2
2
 
3
3
  require 'securerandom'
4
4
  require 'digest'
5
+ require 'base64'
5
6
  require_relative 'transport/tcp_connection'
6
7
  require_relative 'transport/abridged_packet_codec'
7
8
  require_relative 'tl/message'
9
+ require_relative 'client/rpc'
10
+ require_relative 'tl/method_builder'
8
11
 
9
12
  module MTProto
10
13
  class Client
11
- attr_reader :connection, :server_key, :auth_key, :server_salt, :time_offset, :session, :timeout
12
- attr_accessor :api_id, :api_hash, :device_model, :system_version, :app_version, :system_lang_code, :lang_pack, :lang_code
14
+ include TL::MethodBuilder
13
15
 
14
- CONSTRUCTOR_MSGS_ACK = 0x62d6b459
16
+ attr_reader :connection, :server_key, :auth_key, :server_salt, :time_offset, :session, :timeout, :user_id, :access_hash, :dc_number
17
+ attr_accessor :api_id, :api_hash, :device_model, :system_version, :app_version, :system_lang_code, :lang_pack, :lang_code
15
18
 
16
19
  def initialize(api_id: nil, api_hash: nil, host:, port: 443, public_key: nil, dc_number: nil, test_mode: false, timeout: 10)
17
20
  raise ArgumentError, "host is required" if host.nil? || host.empty?
@@ -29,6 +32,8 @@ module MTProto
29
32
  @time_offset = 0
30
33
  @session = nil
31
34
  @connection_initialized = false
35
+ @user_id = nil
36
+ @access_hash = nil
32
37
 
33
38
  # Client configuration defaults
34
39
  @api_id = api_id || 0
@@ -49,25 +54,7 @@ module MTProto
49
54
  @connection.close if @connection
50
55
  end
51
56
 
52
- def req_pq_multi
53
- nonce = SecureRandom.random_bytes(16)
54
-
55
- message = TL::Message.req_pq_multi(nonce)
56
- payload = message.serialize
57
-
58
- @connection.send(payload)
59
-
60
- response_data = @connection.recv(timeout: @timeout)
61
- response_message = TL::Message.deserialize(response_data)
62
-
63
- res_pq = response_message.parse_res_pq
64
-
65
- raise 'Nonce mismatch!' unless res_pq[:nonce] == nonce
66
-
67
- res_pq
68
- end
69
-
70
- def make_auth_key
57
+ def exchange_keys!
71
58
  raise ArgumentError, "public_key is required for auth key generation" if @public_key.nil? || @public_key.empty?
72
59
 
73
60
  generator = AuthKeyGenerator.new(@connection, @public_key, @dc_number, test_mode: @test_mode, timeout: @timeout)
@@ -81,175 +68,43 @@ module MTProto
81
68
  result
82
69
  end
83
70
 
84
- def generate_msg_id
85
- time = Time.now.to_f + @time_offset
86
- msg_id = (time * (2**32)).to_i
87
- (msg_id / 4) * 4
71
+ def rpc
72
+ @rpc ||= RPC.new(self)
88
73
  end
89
74
 
90
- def rpc_call(body, content_related: true)
91
- raise 'Auth key not generated' unless @auth_key
92
- raise 'Session not initialized' unless @session
93
-
94
- msg_id = generate_msg_id
95
- seq_no = @session.next_seq_no(content_related: content_related)
75
+ def save_session
76
+ raise 'Cannot save session: auth_key not set' unless @auth_key
96
77
 
97
- encrypted_msg = EncryptedMessage.encrypt(
98
- auth_key: @auth_key,
78
+ {
79
+ auth_key: Base64.strict_encode64(@auth_key),
99
80
  server_salt: @server_salt,
100
- session_id: @session.session_id,
101
- msg_id: msg_id,
102
- seq_no: seq_no,
103
- body: body
104
- )
105
-
106
- @connection.send(encrypted_msg.serialize)
107
-
108
- response_data = @connection.recv(timeout: @timeout)
109
-
110
- decrypted = EncryptedMessage.decrypt(
111
- auth_key: @auth_key,
112
- encrypted_message_data: response_data,
113
- sender: :server
114
- )
115
-
116
- response_body = decrypted[:body]
117
-
118
- constructor = response_body[0, 4].unpack1('L<')
119
-
120
- if constructor == TL::NewSessionCreated::CONSTRUCTOR
121
- session_info = TL::NewSessionCreated.deserialize(response_body)
122
- @server_salt = session_info.server_salt
123
-
124
- response_data = @connection.recv(timeout: @timeout)
125
- decrypted = EncryptedMessage.decrypt(
126
- auth_key: @auth_key,
127
- encrypted_message_data: response_data,
128
- sender: :server
129
- )
130
- response_body = decrypted[:body]
131
- constructor = response_body[0, 4].unpack1('L<')
132
- end
133
-
134
- if constructor == TL::Message::CONSTRUCTOR_MSG_CONTAINER
135
- container = TL::MsgContainer.deserialize(response_body)
136
-
137
- rpc_result = container.messages.find do |msg|
138
- msg[:body][0, 4].unpack1('L<') == 0xf35c6d01
139
- end
140
-
141
- return rpc_result[:body][12..] if rpc_result
142
-
143
- new_session = container.messages.find { |msg| msg[:body][0, 4].unpack1('L<') == TL::NewSessionCreated::CONSTRUCTOR }
144
- if new_session
145
- session_info = TL::NewSessionCreated.deserialize(new_session[:body])
146
- @server_salt = session_info.server_salt
147
-
148
- other_messages = container.messages.reject do |msg|
149
- constructor = msg[:body][0, 4].unpack1('L<')
150
- constructor == TL::NewSessionCreated::CONSTRUCTOR || constructor == CONSTRUCTOR_MSGS_ACK
151
- end
152
-
153
- if !other_messages.empty?
154
- return other_messages.first[:body]
155
- end
156
-
157
- response_data = @connection.recv(timeout: @timeout)
158
- decrypted = EncryptedMessage.decrypt(
159
- auth_key: @auth_key,
160
- encrypted_message_data: response_data,
161
- sender: :server
162
- )
163
- response_body = decrypted[:body]
164
- constructor = response_body[0, 4].unpack1('L<')
165
-
166
- return response_body[12..] if constructor == 0xf35c6d01
167
-
168
- if constructor == TL::Message::CONSTRUCTOR_MSG_CONTAINER
169
- container = TL::MsgContainer.deserialize(response_body)
170
- rpc_result = container.messages.find { |msg| msg[:body][0, 4].unpack1('L<') == 0xf35c6d01 }
171
- return rpc_result[:body][12..] if rpc_result
172
- end
173
-
174
- return response_body
175
- end
176
-
177
- return container.messages.first[:body]
178
- end
179
-
180
- return response_body[12..] if constructor == 0xf35c6d01
181
-
182
- response_body
81
+ user_id: @user_id,
82
+ access_hash: @access_hash,
83
+ dc_number: @dc_number,
84
+ time_offset: @time_offset
85
+ }
183
86
  end
184
87
 
185
- def invoke_with_layer(layer, query)
186
- body = TL::Serializer.serialize_int(0xda9b0d0d)
187
- body += TL::Serializer.serialize_int(layer)
188
- body += query
189
- body
190
- end
88
+ def load_session(session_data)
89
+ raise ArgumentError, 'session_data must be a Hash' unless session_data.is_a?(Hash)
90
+ raise ArgumentError, 'auth_key is required' unless session_data[:auth_key]
91
+ raise ArgumentError, 'server_salt is required' unless session_data[:server_salt]
191
92
 
192
- def init_connection(api_id:, device_model:, system_version:, app_version:, system_lang_code:, lang_pack:, lang_code:, query:)
193
- body = TL::Serializer.serialize_int(0xc1cd5ea9)
194
- flags = 0
195
- body += TL::Serializer.serialize_int(flags)
196
- body += TL::Serializer.serialize_int(api_id)
197
- body += TL::Serializer.serialize_string(device_model)
198
- body += TL::Serializer.serialize_string(system_version)
199
- body += TL::Serializer.serialize_string(app_version)
200
- body += TL::Serializer.serialize_string(system_lang_code)
201
- body += TL::Serializer.serialize_string(lang_pack)
202
- body += TL::Serializer.serialize_string(lang_code)
203
- body += query
204
- body
205
- end
93
+ @auth_key = Base64.strict_decode64(session_data[:auth_key])
94
+ @server_salt = session_data[:server_salt]
95
+ @time_offset = session_data[:time_offset] || 0
96
+ @user_id = session_data[:user_id]
97
+ @access_hash = session_data[:access_hash]
98
+
99
+ # Create a fresh session for the new connection
100
+ @session = Session.new
206
101
 
207
- def help_get_config
208
- query = [0xc4f9186b].pack('L<')
209
-
210
- unless @connection_initialized
211
- query = init_connection(
212
- api_id: @api_id,
213
- device_model: @device_model,
214
- system_version: @system_version,
215
- app_version: @app_version,
216
- system_lang_code: @system_lang_code,
217
- lang_pack: @lang_pack,
218
- lang_code: @lang_code,
219
- query: query
220
- )
221
- query = invoke_with_layer(214, query)
222
- @connection_initialized = true
223
- end
224
-
225
- rpc_call(query)
102
+ true
226
103
  end
227
104
 
228
- def auth_send_code(phone_number, code_settings: {})
229
- raise ArgumentError, 'phone_number is required' if phone_number.nil? || phone_number.empty?
230
-
231
- query = [0xa677244f].pack('L<')
232
- query += TL::Serializer.serialize_string(phone_number)
233
- query += TL::Serializer.serialize_int(@api_id)
234
- query += TL::Serializer.serialize_string(@api_hash)
235
- query += TL::CodeSettings.serialize(code_settings)
236
-
237
- unless @connection_initialized
238
- query = init_connection(
239
- api_id: @api_id,
240
- device_model: @device_model,
241
- system_version: @system_version,
242
- app_version: @app_version,
243
- system_lang_code: @system_lang_code,
244
- lang_pack: @lang_pack,
245
- lang_code: @lang_code,
246
- query: query
247
- )
248
- query = invoke_with_layer(214, query)
249
- @connection_initialized = true
250
- end
251
-
252
- rpc_call(query)
105
+ def update_user(user_id:, access_hash: nil)
106
+ @user_id = user_id
107
+ @access_hash = access_hash
253
108
  end
254
109
  end
255
110
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  begin
4
- require 'aes_ige/aes_ige'
4
+ require 'aes_ige'
5
5
  rescue LoadError => e
6
6
  warn "Failed to load AES-IGE C extension: #{e.message}"
7
7
  warn 'Run: cd ext/aes_ige && ruby extconf.rb && make'
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  begin
4
- require 'factorization/factorization'
4
+ require 'factorization'
5
5
  rescue LoadError => e
6
6
  warn "Failed to load Factorization C extension: #{e.message}"
7
7
  warn 'Run: cd ext/factorization && ruby extconf.rb && make'
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module MessageId
5
+ module_function
6
+
7
+ def generate(time_offset: 0)
8
+ time = Time.now.to_f + time_offset
9
+ msg_id = (time * (2**32)).to_i
10
+ (msg_id / 4) * 4
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../tl/rpc/help/get_config'
4
+ require_relative '../tl/rpc/help/config'
5
+
6
+ module MTProto
7
+ module RPC
8
+ class GetConfig
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+ def call
14
+ query = TL::RPC::Help::GetConfig.build
15
+
16
+ unless @client.instance_variable_get(:@connection_initialized)
17
+ query = @client.init_connection(
18
+ api_id: @client.api_id,
19
+ device_model: @client.device_model,
20
+ system_version: @client.system_version,
21
+ app_version: @client.app_version,
22
+ system_lang_code: @client.system_lang_code,
23
+ lang_pack: @client.lang_pack,
24
+ lang_code: @client.lang_code,
25
+ query: query
26
+ )
27
+ query = @client.invoke_with_layer(214, query)
28
+ @client.instance_variable_set(:@connection_initialized, true)
29
+ end
30
+
31
+ response = @client.rpc.call(query)
32
+
33
+ TL::RPC::Help::Config.parse(response)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../tl/rpc/contacts/get_contacts'
4
+ require_relative '../tl/rpc/contacts/contacts'
5
+
6
+ module MTProto
7
+ module RPC
8
+ class GetContacts
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+ def call(hash: 0)
14
+ raise 'Auth key not generated' unless @client.auth_key
15
+
16
+ query = TL::RPC::Contacts::GetContacts.build(hash: hash)
17
+ response = @client.rpc.call(query)
18
+ TL::RPC::Contacts::Contacts.parse(response)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../tl/rpc/updates/get_difference'
4
+ require_relative '../tl/rpc/updates/difference'
5
+
6
+ module MTProto
7
+ module RPC
8
+ class GetUpdatesDifference
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+ def call(pts:, date:, qts:, pts_limit: 100, qts_limit: 100, pts_total_limit: nil)
14
+ raise 'Auth key not generated' unless @client.auth_key
15
+ raise ArgumentError, 'pts is required' if pts.nil?
16
+ raise ArgumentError, 'date is required' if date.nil?
17
+ raise ArgumentError, 'qts is required' if qts.nil?
18
+
19
+ query = TL::RPC::Updates::GetDifference.build(
20
+ pts: pts,
21
+ pts_limit: pts_limit,
22
+ pts_total_limit: pts_total_limit,
23
+ date: date,
24
+ qts: qts,
25
+ qts_limit: qts_limit
26
+ )
27
+
28
+ response = @client.rpc.call(query)
29
+ TL::RPC::Updates::Difference.parse(response)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../tl/rpc/updates/get_state'
4
+ require_relative '../tl/rpc/updates/state'
5
+
6
+ module MTProto
7
+ module RPC
8
+ class GetUpdatesState
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+ def call
14
+ raise 'Auth key not generated' unless @client.auth_key
15
+
16
+ query = TL::RPC::Updates::GetState.build
17
+ response = @client.rpc.call(query)
18
+ TL::RPC::Updates::State.parse(response)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../tl/rpc/users/get_users'
4
+ require_relative '../tl/rpc/users/users'
5
+
6
+ module MTProto
7
+ module RPC
8
+ class GetUsers
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+ def call
14
+ raise 'Auth key not generated' unless @client.auth_key
15
+
16
+ query = TL::RPC::Users::GetUsers.build
17
+ response = @client.rpc.call(query)
18
+ TL::RPC::Users::Users.parse(response)
19
+ end
20
+ end
21
+ end
22
+ end