mtproto 0.0.8 → 0.0.10

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 (132) hide show
  1. checksums.yaml +4 -4
  2. data/data/tl-schema.json +42686 -0
  3. data/ext/aes_ige/extconf.rb +3 -9
  4. data/ext/factorization/extconf.rb +2 -0
  5. data/lib/mtproto/auth_key_generator.rb +68 -105
  6. data/lib/mtproto/binary.rb +21 -0
  7. data/lib/mtproto/client/api/check_password.rb +41 -0
  8. data/lib/mtproto/client/api/export_login_token.rb +27 -0
  9. data/lib/mtproto/client/api/get_dialogs.rb +21 -0
  10. data/lib/mtproto/client/api/get_history.rb +20 -0
  11. data/lib/mtproto/client/api/get_updates_difference.rb +21 -0
  12. data/lib/mtproto/client/api/get_updates_state.rb +14 -0
  13. data/lib/mtproto/client/api/get_users.rb +14 -0
  14. data/lib/mtproto/client/api/import_login_token.rb +23 -0
  15. data/lib/mtproto/client/api/send_code.rb +21 -0
  16. data/lib/mtproto/client/api/sign_in.rb +27 -0
  17. data/lib/mtproto/client/api.rb +36 -0
  18. data/lib/mtproto/client/rpc/response.rb +63 -0
  19. data/lib/mtproto/client/rpc.rb +60 -127
  20. data/lib/mtproto/client.rb +143 -32
  21. data/lib/mtproto/crypto/dh_key_exchange.rb +1 -2
  22. data/lib/mtproto/crypto/dh_validator.rb +17 -19
  23. data/lib/mtproto/crypto/factorization.rb +1 -1
  24. data/lib/mtproto/crypto/rsa_key.rb +2 -2
  25. data/lib/mtproto/crypto/srp.rb +117 -0
  26. data/lib/mtproto/delegate_methods.rb +11 -0
  27. data/lib/mtproto/errors.rb +8 -0
  28. data/lib/mtproto/message/message.rb +85 -0
  29. data/lib/mtproto/session.rb +1 -1
  30. data/lib/mtproto/tl/constructor_names.rb +2271 -0
  31. data/lib/mtproto/tl/constructors.rb +99 -0
  32. data/lib/mtproto/tl/object.rb +25 -0
  33. data/lib/mtproto/tl/objects/account_password.rb +69 -0
  34. data/lib/mtproto/tl/objects/authorization.rb +70 -0
  35. data/lib/mtproto/tl/objects/check_password.rb +43 -0
  36. data/lib/mtproto/tl/objects/client_dh_inner_data.rb +45 -0
  37. data/lib/mtproto/tl/objects/dh_gen_response.rb +46 -0
  38. data/lib/mtproto/tl/objects/dialogs.rb +453 -0
  39. data/lib/mtproto/tl/objects/export_login_token.rb +48 -0
  40. data/lib/mtproto/tl/objects/get_config.rb +13 -0
  41. data/lib/mtproto/tl/objects/get_dialogs.rb +51 -0
  42. data/lib/mtproto/tl/objects/get_difference.rb +34 -0
  43. data/lib/mtproto/tl/objects/get_history.rb +49 -0
  44. data/lib/mtproto/tl/objects/get_password.rb +13 -0
  45. data/lib/mtproto/tl/objects/get_state.rb +13 -0
  46. data/lib/mtproto/tl/objects/get_users.rb +16 -0
  47. data/lib/mtproto/{type → tl/objects}/gzip_packed.rb +6 -6
  48. data/lib/mtproto/tl/objects/help_config.rb +76 -0
  49. data/lib/mtproto/tl/objects/import_login_token.rb +37 -0
  50. data/lib/mtproto/tl/objects/init_connection.rb +57 -0
  51. data/lib/mtproto/tl/objects/invoke_with_layer.rb +20 -0
  52. data/lib/mtproto/tl/objects/login_token.rb +78 -0
  53. data/lib/mtproto/{type → tl/objects}/message.rb +3 -3
  54. data/lib/mtproto/tl/objects/messages.rb +162 -0
  55. data/lib/mtproto/{type → tl/objects}/msg_container.rb +1 -3
  56. data/lib/mtproto/{type → tl/objects}/new_session_created.rb +1 -3
  57. data/lib/mtproto/tl/objects/pq_inner_data.rb +66 -0
  58. data/lib/mtproto/tl/objects/req_dh_params.rb +63 -0
  59. data/lib/mtproto/tl/objects/req_pq_multi.rb +21 -0
  60. data/lib/mtproto/tl/objects/res_pq.rb +73 -0
  61. data/lib/mtproto/{type → tl/objects}/rpc_error.rb +1 -4
  62. data/lib/mtproto/tl/objects/send_code.rb +47 -0
  63. data/lib/mtproto/tl/objects/sent_code.rb +79 -0
  64. data/lib/mtproto/tl/objects/server_dh_inner_data.rb +74 -0
  65. data/lib/mtproto/tl/objects/server_dh_params.rb +53 -0
  66. data/lib/mtproto/tl/objects/set_client_dh_params.rb +46 -0
  67. data/lib/mtproto/tl/objects/sign_in.rb +45 -0
  68. data/lib/mtproto/tl/objects/update.rb +77 -0
  69. data/lib/mtproto/tl/objects/update_short.rb +20 -0
  70. data/lib/mtproto/tl/objects/update_short_message.rb +65 -0
  71. data/lib/mtproto/tl/objects/updates_difference.rb +152 -0
  72. data/lib/mtproto/tl/objects/updates_state.rb +35 -0
  73. data/lib/mtproto/tl/objects/users.rb +83 -0
  74. data/lib/mtproto/tl/schema.rb +102 -0
  75. data/lib/mtproto/transport/abridged_packet_codec.rb +35 -12
  76. data/lib/mtproto/transport/connection.rb +23 -0
  77. data/lib/mtproto/transport/errors.rb +11 -0
  78. data/lib/mtproto/transport/packet.rb +19 -0
  79. data/lib/mtproto/transport/tcp_connection.rb +57 -46
  80. data/lib/mtproto/updates_poller.rb +37 -33
  81. data/lib/mtproto/version.rb +1 -1
  82. data/lib/mtproto.rb +17 -27
  83. data/scripts/generate_constructors.rb +65 -0
  84. metadata +76 -61
  85. data/lib/mtproto/async/middleware/base.rb +0 -17
  86. data/lib/mtproto/async/middleware/flood_wait.rb +0 -42
  87. data/lib/mtproto/async/request.rb +0 -18
  88. data/lib/mtproto/async/request_queue.rb +0 -63
  89. data/lib/mtproto/async_client.rb +0 -201
  90. data/lib/mtproto/rpc/get_config.rb +0 -34
  91. data/lib/mtproto/rpc/get_contacts.rb +0 -29
  92. data/lib/mtproto/rpc/get_updates_difference.rb +0 -51
  93. data/lib/mtproto/rpc/get_updates_state.rb +0 -29
  94. data/lib/mtproto/rpc/get_users.rb +0 -29
  95. data/lib/mtproto/rpc/ping.rb +0 -33
  96. data/lib/mtproto/rpc/send_code.rb +0 -41
  97. data/lib/mtproto/rpc/send_message.rb +0 -47
  98. data/lib/mtproto/rpc/sign_in.rb +0 -48
  99. data/lib/mtproto/type/auth_key/dh_gen_response.rb +0 -37
  100. data/lib/mtproto/type/auth_key/req_dh_params.rb +0 -31
  101. data/lib/mtproto/type/auth_key/req_pq_multi.rb +0 -18
  102. data/lib/mtproto/type/auth_key/res_pq.rb +0 -62
  103. data/lib/mtproto/type/auth_key/server_dh_params.rb +0 -43
  104. data/lib/mtproto/type/auth_key/set_client_dh_params.rb +0 -25
  105. data/lib/mtproto/type/bad_msg_notification.rb +0 -46
  106. data/lib/mtproto/type/client_dh_inner_data.rb +0 -29
  107. data/lib/mtproto/type/code_settings.rb +0 -25
  108. data/lib/mtproto/type/config.rb +0 -124
  109. data/lib/mtproto/type/pq_inner_data.rb +0 -41
  110. data/lib/mtproto/type/rpc/auth/authorization.rb +0 -107
  111. data/lib/mtproto/type/rpc/auth/send_code.rb +0 -28
  112. data/lib/mtproto/type/rpc/auth/sent_code.rb +0 -36
  113. data/lib/mtproto/type/rpc/auth/sign_in.rb +0 -32
  114. data/lib/mtproto/type/rpc/contacts/contacts.rb +0 -155
  115. data/lib/mtproto/type/rpc/contacts/get_contacts.rb +0 -18
  116. data/lib/mtproto/type/rpc/help/config.rb +0 -35
  117. data/lib/mtproto/type/rpc/help/get_config.rb +0 -17
  118. data/lib/mtproto/type/rpc/init_connection.rb +0 -28
  119. data/lib/mtproto/type/rpc/invoke_with_layer.rb +0 -19
  120. data/lib/mtproto/type/rpc/messages/send_message.rb +0 -43
  121. data/lib/mtproto/type/rpc/messages/updates.rb +0 -87
  122. data/lib/mtproto/type/rpc/ping.rb +0 -18
  123. data/lib/mtproto/type/rpc/pong.rb +0 -46
  124. data/lib/mtproto/type/rpc/updates/difference.rb +0 -332
  125. data/lib/mtproto/type/rpc/updates/get_difference.rb +0 -42
  126. data/lib/mtproto/type/rpc/updates/get_state.rb +0 -17
  127. data/lib/mtproto/type/rpc/updates/state.rb +0 -59
  128. data/lib/mtproto/type/rpc/users/get_users.rb +0 -25
  129. data/lib/mtproto/type/rpc/users/users.rb +0 -99
  130. data/lib/mtproto/type/sent_code.rb +0 -128
  131. data/lib/mtproto/type/serializer.rb +0 -55
  132. data/lib/mtproto/type/server_dh_inner_data.rb +0 -85
@@ -1,201 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'concurrent'
4
- require_relative 'async/request'
5
- require_relative 'async/request_queue'
6
- require_relative 'async/middleware/base'
7
- require_relative 'async/middleware/flood_wait'
8
-
9
- module MTProto
10
- class AsyncClient
11
- attr_reader :client
12
-
13
- def initialize(client)
14
- @client = client
15
- @queue = Async::RequestQueue.new
16
- @middleware_classes = []
17
- @pending_requests = Concurrent::Hash.new
18
- @timeout_threads = Concurrent::Hash.new
19
- @receiver_thread = nil
20
- @running = Concurrent::AtomicBoolean.new(false)
21
-
22
- use(Async::Middleware::FloodWait)
23
- end
24
-
25
- def use(middleware_class, **options)
26
- @middleware_classes << [middleware_class, options]
27
- self
28
- end
29
-
30
- def call(body, metadata: {})
31
- ensure_receiver_running!
32
-
33
- request = Async::Request.new(body: body, metadata: metadata)
34
-
35
- @queue.call(key: request.key) do
36
- send_and_wrap = lambda do |retries = 0|
37
- base_future = send_request(request.body)
38
-
39
- retry_fn = lambda do
40
- send_and_wrap.call(retries + 1)
41
- end
42
-
43
- build_middleware_stack.call(request, base_future, retry_fn, retries)
44
- end
45
-
46
- send_and_wrap.call(0)
47
- end
48
- end
49
-
50
- def shutdown
51
- @running.make_false
52
-
53
- @client.disconnect! if @client.connected?
54
-
55
- if @receiver_thread
56
- @receiver_thread.join(2)
57
- @receiver_thread.kill if @receiver_thread.alive?
58
- @receiver_thread = nil
59
- end
60
-
61
- @timeout_threads.each_value(&:kill)
62
- @timeout_threads.clear
63
-
64
- @pending_requests.each_value do |future|
65
- future.reject(MTProto::Transport::ConnectionError.new('Client shutting down')) unless future.resolved?
66
- end
67
- @pending_requests.clear
68
-
69
- @queue.shutdown
70
- end
71
-
72
- private
73
-
74
- def send_request(body)
75
- msg_id = @client.rpc.call(body)
76
- future = Concurrent::Promises.resolvable_future
77
- @pending_requests[msg_id] = future
78
-
79
- timeout_thread = Thread.new do
80
- sleep @client.timeout
81
- if @pending_requests.delete(msg_id)
82
- future.reject(MTProto::Transport::ConnectionError.new('RPC timeout'))
83
- end
84
- @timeout_threads.delete(msg_id)
85
- end
86
- @timeout_threads[msg_id] = timeout_thread
87
-
88
- future.on_fulfillment! do
89
- timeout_thread.kill
90
- @timeout_threads.delete(msg_id)
91
- end
92
- future.on_rejection! do
93
- timeout_thread.kill
94
- @timeout_threads.delete(msg_id)
95
- end
96
-
97
- future
98
- end
99
-
100
- def ensure_receiver_running!
101
- return if @running.true?
102
-
103
- @running.make_true
104
- @receiver_thread = Thread.new { receiver_loop }
105
- end
106
-
107
- def receiver_loop
108
- loop do
109
- break unless @running.true?
110
-
111
- begin
112
- response_data = @client.connection.recv(timeout: 1)
113
-
114
- decrypted = EncryptedMessage.decrypt(
115
- auth_key: @client.auth_key,
116
- encrypted_message_data: response_data,
117
- sender: :server
118
- )
119
-
120
- process_message(decrypted[:body])
121
- rescue MTProto::Transport::ConnectionError => e
122
- next if e.message == 'Receive timeout' && @running.true?
123
- break
124
- rescue IOError => e
125
- break
126
- rescue => e
127
- warn "AsyncClient receiver error: #{e.class}: #{e.message}"
128
- warn e.backtrace.join("\n")
129
- break
130
- end
131
- end
132
- end
133
-
134
- def process_message(response_body)
135
- constructor = response_body[0, 4].unpack1('L<')
136
-
137
- case constructor
138
- when Client::RPC::CONSTRUCTOR_BAD_SERVER_SALT
139
- handle_bad_server_salt(response_body)
140
- when Type::NewSessionCreated::CONSTRUCTOR
141
- handle_new_session(response_body)
142
- when Type::MsgContainer::CONSTRUCTOR
143
- handle_container(response_body)
144
- when Client::RPC::CONSTRUCTOR_RPC_RESULT
145
- handle_rpc_result(response_body)
146
- end
147
- end
148
-
149
- def handle_bad_server_salt(response_body)
150
- offset = 4
151
- offset += 8
152
- offset += 4
153
- offset += 4
154
- new_server_salt = response_body[offset, 8].unpack1('Q<')
155
-
156
- @client.instance_variable_set(:@server_salt, new_server_salt)
157
- end
158
-
159
- def handle_new_session(response_body)
160
- session_info = Type::NewSessionCreated.deserialize(response_body)
161
- @client.instance_variable_set(:@server_salt, session_info.server_salt)
162
- end
163
-
164
- def handle_container(response_body)
165
- container = Type::MsgContainer.deserialize(response_body)
166
-
167
- container.messages.each do |msg|
168
- process_message(msg[:body])
169
- end
170
- end
171
-
172
- def handle_rpc_result(response_body)
173
- offset = 4
174
- req_msg_id = response_body[offset, 8].unpack1('Q<')
175
- offset += 8
176
- result = response_body[offset..]
177
-
178
- future = @pending_requests.delete(req_msg_id)
179
- return unless future # No pending request for this msg_id
180
-
181
- # Check if result is an RPC error
182
- result_constructor = result[0, 4].unpack1('L<')
183
- if result_constructor == Type::RpcError::CONSTRUCTOR
184
- error = Type::RpcError.deserialize(result)
185
- future.reject(MTProto::RpcError.new(error.error_code, error.error_message))
186
- else
187
- future.fulfill(result)
188
- end
189
- end
190
-
191
- def build_middleware_stack
192
- # Middleware now wraps Futures and can trigger retries
193
- # The base "app" just returns the Future as-is
194
- app = ->(request, future, retry_fn, retries) { future }
195
-
196
- @middleware_classes.reverse.reduce(app) do |stack, (middleware_class, options)|
197
- middleware_class.new(stack, **options)
198
- end
199
- end
200
- end
201
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../type/rpc/help/get_config'
4
- require_relative '../type/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 = build_query
15
-
16
- @client.rpc.call(query)
17
- end
18
-
19
- def call_sync
20
- query = build_query
21
-
22
- response = @client.rpc.call_sync(query)
23
-
24
- Type::RPC::Help::Config.parse(response)
25
- end
26
-
27
- private
28
-
29
- def build_query
30
- Type::RPC::Help::GetConfig.build
31
- end
32
- end
33
- end
34
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../type/rpc/contacts/get_contacts'
4
- require_relative '../type/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 = Type::RPC::Contacts::GetContacts.build(hash: hash)
17
- @client.rpc.call(query)
18
- end
19
-
20
- def call_sync(hash: 0)
21
- raise 'Auth key not generated' unless @client.auth_key
22
-
23
- query = Type::RPC::Contacts::GetContacts.build(hash: hash)
24
- response = @client.rpc.call_sync(query)
25
- Type::RPC::Contacts::Contacts.parse(response)
26
- end
27
- end
28
- end
29
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../type/rpc/updates/get_difference'
4
- require_relative '../type/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 = Type::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
- @client.rpc.call(query)
29
- end
30
-
31
- def call_sync(pts:, date:, qts:, pts_limit: 100, qts_limit: 100, pts_total_limit: nil)
32
- raise 'Auth key not generated' unless @client.auth_key
33
- raise ArgumentError, 'pts is required' if pts.nil?
34
- raise ArgumentError, 'date is required' if date.nil?
35
- raise ArgumentError, 'qts is required' if qts.nil?
36
-
37
- query = Type::RPC::Updates::GetDifference.build(
38
- pts: pts,
39
- pts_limit: pts_limit,
40
- pts_total_limit: pts_total_limit,
41
- date: date,
42
- qts: qts,
43
- qts_limit: qts_limit
44
- )
45
-
46
- response = @client.rpc.call_sync(query)
47
- Type::RPC::Updates::Difference.parse(response)
48
- end
49
- end
50
- end
51
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../type/rpc/updates/get_state'
4
- require_relative '../type/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 = Type::RPC::Updates::GetState.build
17
- @client.rpc.call(query)
18
- end
19
-
20
- def call_sync
21
- raise 'Auth key not generated' unless @client.auth_key
22
-
23
- query = Type::RPC::Updates::GetState.build
24
- response = @client.rpc.call_sync(query)
25
- Type::RPC::Updates::State.parse(response)
26
- end
27
- end
28
- end
29
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../type/rpc/users/get_users'
4
- require_relative '../type/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 = Type::RPC::Users::GetUsers.build
17
- @client.rpc.call(query)
18
- end
19
-
20
- def call_sync
21
- raise 'Auth key not generated' unless @client.auth_key
22
-
23
- query = Type::RPC::Users::GetUsers.build
24
- response = @client.rpc.call_sync(query)
25
- Type::RPC::Users::Users.parse(response)
26
- end
27
- end
28
- end
29
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../type/rpc/ping'
4
- require_relative '../type/rpc/pong'
5
-
6
- module MTProto
7
- module RPC
8
- class Ping
9
- def initialize(client)
10
- @client = client
11
- end
12
-
13
- def call(ping_id = nil)
14
- ping_id ||= rand(2**63)
15
- body = Type::RPC::Ping.build(ping_id)
16
-
17
- @client.rpc.call(body)
18
- end
19
-
20
- def call_sync(ping_id = nil)
21
- ping_id ||= rand(2**63)
22
- body = Type::RPC::Ping.build(ping_id)
23
-
24
- response_body = @client.rpc.call_sync(body)
25
- pong = Type::RPC::Pong.parse(response_body)
26
-
27
- raise PingMismatchError unless pong[:ping_id] == ping_id
28
-
29
- true
30
- end
31
- end
32
- end
33
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../type/rpc/auth/send_code'
4
- require_relative '../type/rpc/auth/sent_code'
5
-
6
- module MTProto
7
- module RPC
8
- class SendCode
9
- def initialize(client)
10
- @client = client
11
- end
12
-
13
- def call(phone_number, code_settings: {})
14
- query = build_query(phone_number, code_settings)
15
-
16
- @client.rpc.call(query)
17
- end
18
-
19
- def call_sync(phone_number, code_settings: {})
20
- query = build_query(phone_number, code_settings)
21
-
22
- response = @client.rpc.call_sync(query)
23
-
24
- Type::RPC::Auth::SentCode.parse(response)
25
- end
26
-
27
- private
28
-
29
- def build_query(phone_number, code_settings)
30
- raise ArgumentError, 'phone_number is required' if phone_number.nil? || phone_number.empty?
31
-
32
- Type::RPC::Auth::SendCode.build(
33
- phone_number: phone_number,
34
- api_id: @client.api_id,
35
- api_hash: @client.api_hash,
36
- code_settings: code_settings
37
- )
38
- end
39
- end
40
- end
41
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../type/rpc/messages/send_message'
4
- require_relative '../type/rpc/messages/updates'
5
-
6
- module MTProto
7
- module RPC
8
- class SendMessage
9
- def initialize(client)
10
- @client = client
11
- end
12
-
13
- def call(user_id:, access_hash:, message:, random_id: nil)
14
- raise 'Auth key not generated' unless @client.auth_key
15
- raise ArgumentError, 'user_id is required' if user_id.nil?
16
- raise ArgumentError, 'access_hash is required' if access_hash.nil?
17
- raise ArgumentError, 'message is required and cannot be empty' if message.nil? || message.empty?
18
-
19
- query = Type::RPC::Messages::SendMessage.build(
20
- user_id: user_id,
21
- access_hash: access_hash,
22
- message: message,
23
- random_id: random_id
24
- )
25
-
26
- @client.rpc.call(query)
27
- end
28
-
29
- def call_sync(user_id:, access_hash:, message:, random_id: nil)
30
- raise 'Auth key not generated' unless @client.auth_key
31
- raise ArgumentError, 'user_id is required' if user_id.nil?
32
- raise ArgumentError, 'access_hash is required' if access_hash.nil?
33
- raise ArgumentError, 'message is required and cannot be empty' if message.nil? || message.empty?
34
-
35
- query = Type::RPC::Messages::SendMessage.build(
36
- user_id: user_id,
37
- access_hash: access_hash,
38
- message: message,
39
- random_id: random_id
40
- )
41
-
42
- response = @client.rpc.call_sync(query)
43
- Type::RPC::Messages::Updates.parse(response)
44
- end
45
- end
46
- end
47
- end
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../type/rpc/auth/sign_in'
4
- require_relative '../type/rpc/auth/authorization'
5
-
6
- module MTProto
7
- module RPC
8
- class SignIn
9
- def initialize(client)
10
- @client = client
11
- end
12
-
13
- def call(phone_number:, phone_code_hash:, phone_code:)
14
- query = build_query(phone_number, phone_code_hash, phone_code)
15
-
16
- @client.rpc.call(query)
17
- end
18
-
19
- def call_sync(phone_number:, phone_code_hash:, phone_code:)
20
- query = build_query(phone_number, phone_code_hash, phone_code)
21
-
22
- response = @client.rpc.call_sync(query)
23
-
24
- result = Type::RPC::Auth::Authorization.parse(response)
25
-
26
- if result[:authorization] && result[:user_id]
27
- @client.update_user(user_id: result[:user_id], access_hash: result[:access_hash])
28
- end
29
-
30
- result
31
- end
32
-
33
- private
34
-
35
- def build_query(phone_number, phone_code_hash, phone_code)
36
- raise ArgumentError, 'phone_number is required' if phone_number.nil? || phone_number.empty?
37
- raise ArgumentError, 'phone_code_hash is required' if phone_code_hash.nil? || phone_code_hash.empty?
38
- raise ArgumentError, 'phone_code is required' if phone_code.nil? || phone_code.empty?
39
-
40
- Type::RPC::Auth::SignIn.build(
41
- phone_number: phone_number,
42
- phone_code_hash: phone_code_hash,
43
- phone_code: phone_code
44
- )
45
- end
46
- end
47
- end
48
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MTProto
4
- module Type
5
- module AuthKey
6
- class DHGenResponse
7
- CONSTRUCTOR_DH_GEN_OK = 0x3bcbf734
8
- CONSTRUCTOR_DH_GEN_RETRY = 0x46dc1fb9
9
- CONSTRUCTOR_DH_GEN_FAIL = 0xa69dae02
10
-
11
- def self.parse(body)
12
- constructor = body[0, 4].unpack1('L<')
13
-
14
- offset = 4
15
- nonce = body[offset, 16]
16
- offset += 16
17
-
18
- server_nonce = body[offset, 16]
19
- offset += 16
20
-
21
- new_nonce_hash = body[offset, 16]
22
-
23
- case constructor
24
- when CONSTRUCTOR_DH_GEN_OK
25
- { status: :ok, nonce: nonce, server_nonce: server_nonce, new_nonce_hash: new_nonce_hash }
26
- when CONSTRUCTOR_DH_GEN_RETRY
27
- { status: :retry, nonce: nonce, server_nonce: server_nonce, new_nonce_hash: new_nonce_hash }
28
- when CONSTRUCTOR_DH_GEN_FAIL
29
- { status: :fail, nonce: nonce, server_nonce: server_nonce, new_nonce_hash: new_nonce_hash }
30
- else
31
- raise "Unexpected constructor: 0x#{constructor.to_s(16)}"
32
- end
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../serializer'
4
-
5
- module MTProto
6
- module Type
7
- module AuthKey
8
- class ReqDHParams
9
- CONSTRUCTOR = 0xd712e4be
10
-
11
- def self.build(nonce:, server_nonce:, p:, q:, public_key_fingerprint:, encrypted_data:)
12
- raise ArgumentError, 'Nonce must be 16 bytes' unless nonce.bytesize == 16
13
- raise ArgumentError, 'Server nonce must be 16 bytes' unless server_nonce.bytesize == 16
14
-
15
- p_bytes = Serializer.integer_to_bytes(p)
16
- q_bytes = Serializer.integer_to_bytes(q)
17
-
18
- body = Serializer.serialize_int(CONSTRUCTOR)
19
- body += nonce
20
- body += server_nonce
21
- body += Serializer.serialize_bytes(p_bytes)
22
- body += Serializer.serialize_bytes(q_bytes)
23
- body += Serializer.serialize_long(public_key_fingerprint)
24
- body += Serializer.serialize_bytes(encrypted_data)
25
-
26
- body
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MTProto
4
- module Type
5
- module AuthKey
6
- class ReqPqMulti
7
- CONSTRUCTOR = 0xbe7e8ef1
8
-
9
- def self.build(nonce)
10
- raise ArgumentError, 'Nonce must be 16 bytes' unless nonce.bytesize == 16
11
-
12
- constructor = [CONSTRUCTOR].pack('L<')
13
- constructor + nonce
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MTProto
4
- module Type
5
- module AuthKey
6
- class ResPq
7
- CONSTRUCTOR = 0x05162463
8
-
9
- def self.parse(body)
10
- constructor = body[0, 4].unpack1('L<')
11
- raise "Unexpected constructor: 0x#{constructor.to_s(16)}" unless constructor == CONSTRUCTOR
12
-
13
- offset = 4
14
-
15
- nonce = body[offset, 16]
16
- offset += 16
17
-
18
- server_nonce = body[offset, 16]
19
- offset += 16
20
-
21
- pq_length_byte = body[offset].unpack1('C')
22
- offset += 1
23
-
24
- pq_length = if pq_length_byte == 254
25
- body[offset, 3].unpack1('L<') & 0xffffff
26
- offset += 3
27
- else
28
- pq_length_byte
29
- end
30
-
31
- pq = body[offset, pq_length]
32
- offset += pq_length
33
- offset += padding_length(pq_length + 1)
34
-
35
- vector_constructor = body[offset, 4].unpack1('L<')
36
- offset += 4
37
- raise 'Expected vector constructor' unless vector_constructor == 0x1cb5c415
38
-
39
- fingerprints_count = body[offset, 4].unpack1('L<')
40
- offset += 4
41
-
42
- fingerprints = []
43
- fingerprints_count.times do
44
- fingerprints << body[offset, 8].unpack1('Q<')
45
- offset += 8
46
- end
47
-
48
- {
49
- nonce: nonce,
50
- server_nonce: server_nonce,
51
- pq: pq,
52
- fingerprints: fingerprints
53
- }
54
- end
55
-
56
- def self.padding_length(length)
57
- (4 - (length % 4)) % 4
58
- end
59
- end
60
- end
61
- end
62
- end