mtproto 0.0.6 → 0.0.8
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.
- checksums.yaml +4 -4
- data/.env.example +4 -0
- data/lib/mtproto/async/middleware/base.rb +17 -0
- data/lib/mtproto/async/middleware/flood_wait.rb +42 -0
- data/lib/mtproto/async/request.rb +18 -0
- data/lib/mtproto/async/request_queue.rb +63 -0
- data/lib/mtproto/async_client.rb +201 -0
- data/lib/mtproto/auth_key_generator.rb +22 -12
- data/lib/mtproto/client/rpc.rb +165 -0
- data/lib/mtproto/client.rb +65 -176
- data/lib/mtproto/crypto/aes_ige.rb +1 -1
- data/lib/mtproto/crypto/factorization.rb +1 -1
- data/lib/mtproto/message_id.rb +13 -0
- data/lib/mtproto/rpc/get_config.rb +34 -0
- data/lib/mtproto/rpc/get_contacts.rb +29 -0
- data/lib/mtproto/rpc/get_updates_difference.rb +51 -0
- data/lib/mtproto/rpc/get_updates_state.rb +29 -0
- data/lib/mtproto/rpc/get_users.rb +29 -0
- data/lib/mtproto/rpc/ping.rb +33 -0
- data/lib/mtproto/rpc/send_code.rb +41 -0
- data/lib/mtproto/rpc/send_message.rb +47 -0
- data/lib/mtproto/rpc/sign_in.rb +48 -0
- data/lib/mtproto/type/auth_key/dh_gen_response.rb +37 -0
- data/lib/mtproto/type/auth_key/req_dh_params.rb +31 -0
- data/lib/mtproto/type/auth_key/req_pq_multi.rb +18 -0
- data/lib/mtproto/type/auth_key/res_pq.rb +62 -0
- data/lib/mtproto/type/auth_key/server_dh_params.rb +43 -0
- data/lib/mtproto/type/auth_key/set_client_dh_params.rb +25 -0
- data/lib/mtproto/{tl → type}/bad_msg_notification.rb +1 -1
- data/lib/mtproto/{tl → type}/client_dh_inner_data.rb +1 -1
- data/lib/mtproto/{tl → type}/code_settings.rb +1 -1
- data/lib/mtproto/{tl → type}/config.rb +1 -1
- data/lib/mtproto/{tl → type}/gzip_packed.rb +1 -1
- data/lib/mtproto/type/message.rb +38 -0
- data/lib/mtproto/{tl → type}/msg_container.rb +1 -1
- data/lib/mtproto/{tl → type}/new_session_created.rb +1 -1
- data/lib/mtproto/{tl/p_q_inner_data.rb → type/pq_inner_data.rb} +1 -1
- data/lib/mtproto/type/rpc/auth/authorization.rb +107 -0
- data/lib/mtproto/type/rpc/auth/send_code.rb +28 -0
- data/lib/mtproto/type/rpc/auth/sent_code.rb +36 -0
- data/lib/mtproto/type/rpc/auth/sign_in.rb +32 -0
- data/lib/mtproto/type/rpc/contacts/contacts.rb +155 -0
- data/lib/mtproto/type/rpc/contacts/get_contacts.rb +18 -0
- data/lib/mtproto/type/rpc/help/config.rb +35 -0
- data/lib/mtproto/type/rpc/help/get_config.rb +17 -0
- data/lib/mtproto/type/rpc/init_connection.rb +28 -0
- data/lib/mtproto/type/rpc/invoke_with_layer.rb +19 -0
- data/lib/mtproto/type/rpc/messages/send_message.rb +43 -0
- data/lib/mtproto/type/rpc/messages/updates.rb +87 -0
- data/lib/mtproto/type/rpc/ping.rb +18 -0
- data/lib/mtproto/type/rpc/pong.rb +46 -0
- data/lib/mtproto/type/rpc/updates/difference.rb +332 -0
- data/lib/mtproto/type/rpc/updates/get_difference.rb +42 -0
- data/lib/mtproto/type/rpc/updates/get_state.rb +17 -0
- data/lib/mtproto/type/rpc/updates/state.rb +59 -0
- data/lib/mtproto/type/rpc/users/get_users.rb +25 -0
- data/lib/mtproto/type/rpc/users/users.rb +99 -0
- data/lib/mtproto/{tl → type}/rpc_error.rb +1 -1
- data/lib/mtproto/{tl → type}/sent_code.rb +1 -1
- data/lib/mtproto/{tl → type}/serializer.rb +1 -1
- data/lib/mtproto/{tl → type}/server_dh_inner_data.rb +1 -1
- data/lib/mtproto/updates_poller.rb +111 -0
- data/lib/mtproto/version.rb +1 -1
- data/lib/mtproto.rb +28 -14
- metadata +86 -18
- data/ext/aes_ige/Makefile +0 -273
- data/ext/factorization/Makefile +0 -273
- data/lib/mtproto/connection.rb +0 -103
- data/lib/mtproto/tl/message.rb +0 -252
|
@@ -0,0 +1,37 @@
|
|
|
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
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module Type
|
|
5
|
+
module AuthKey
|
|
6
|
+
class ServerDHParams
|
|
7
|
+
CONSTRUCTOR = 0xd0e8075c
|
|
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
|
+
length_byte = body[offset].ord
|
|
22
|
+
offset += 1
|
|
23
|
+
|
|
24
|
+
if length_byte == 254
|
|
25
|
+
length_bytes = body[offset, 3].bytes
|
|
26
|
+
encrypted_answer_length = length_bytes[0] | (length_bytes[1] << 8) | (length_bytes[2] << 16)
|
|
27
|
+
offset += 3
|
|
28
|
+
else
|
|
29
|
+
encrypted_answer_length = length_byte
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
encrypted_answer = body[offset, encrypted_answer_length]
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
nonce: nonce,
|
|
36
|
+
server_nonce: server_nonce,
|
|
37
|
+
encrypted_answer: encrypted_answer
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../serializer'
|
|
4
|
+
|
|
5
|
+
module MTProto
|
|
6
|
+
module Type
|
|
7
|
+
module AuthKey
|
|
8
|
+
class SetClientDHParams
|
|
9
|
+
CONSTRUCTOR = 0xf5045f1f
|
|
10
|
+
|
|
11
|
+
def self.build(nonce:, server_nonce:, 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
|
+
body = Serializer.serialize_int(CONSTRUCTOR)
|
|
16
|
+
body += nonce
|
|
17
|
+
body += server_nonce
|
|
18
|
+
body += Serializer.serialize_bytes(encrypted_data)
|
|
19
|
+
|
|
20
|
+
body
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module Type
|
|
5
|
+
class Message
|
|
6
|
+
attr_reader :auth_key_id, :msg_id, :body
|
|
7
|
+
|
|
8
|
+
def initialize(auth_key_id:, msg_id:, body:)
|
|
9
|
+
@auth_key_id = auth_key_id
|
|
10
|
+
@msg_id = msg_id
|
|
11
|
+
@body = body
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def serialize
|
|
15
|
+
auth_key_id_bytes = [@auth_key_id].pack('Q<')
|
|
16
|
+
msg_id_bytes = [@msg_id].pack('Q<')
|
|
17
|
+
body_length = [@body.bytesize].pack('L<')
|
|
18
|
+
|
|
19
|
+
auth_key_id_bytes + msg_id_bytes + body_length + @body
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.deserialize(data)
|
|
23
|
+
if data.bytesize < 20
|
|
24
|
+
raise(ArgumentError,
|
|
25
|
+
"Invalid MTProto message: expected at least 20 bytes, got #{data.bytesize} bytes (hex: #{data.unpack1('H*')})",
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
auth_key_id = data[0, 8].unpack1('Q<')
|
|
30
|
+
msg_id = data[8, 8].unpack1('Q<')
|
|
31
|
+
body_length = data[16, 4].unpack1('L<')
|
|
32
|
+
body = data[20, body_length]
|
|
33
|
+
|
|
34
|
+
new(auth_key_id: auth_key_id, msg_id: msg_id, body: body)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../gzip_packed'
|
|
4
|
+
require_relative '../../rpc_error'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module Type
|
|
8
|
+
module RPC
|
|
9
|
+
module Auth
|
|
10
|
+
class Authorization
|
|
11
|
+
CONSTRUCTOR = 0x2ea2c0d4
|
|
12
|
+
CONSTRUCTOR_SIGN_UP_REQUIRED = 0x44747e9a
|
|
13
|
+
|
|
14
|
+
def self.parse(response)
|
|
15
|
+
constructor = response[0, 4].unpack1('L<')
|
|
16
|
+
|
|
17
|
+
if constructor == Type::GzipPacked::CONSTRUCTOR
|
|
18
|
+
response = Type::GzipPacked.unpack(response)
|
|
19
|
+
constructor = response[0, 4].unpack1('L<')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if constructor == Type::RpcError::CONSTRUCTOR
|
|
23
|
+
error = Type::RpcError.deserialize(response)
|
|
24
|
+
raise MTProto::RpcError.new(error.error_code, error.error_message)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
if constructor == CONSTRUCTOR_SIGN_UP_REQUIRED
|
|
28
|
+
return { authorization: nil, sign_up_required: true }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
if constructor == CONSTRUCTOR
|
|
32
|
+
offset = 4
|
|
33
|
+
|
|
34
|
+
# Parse flags
|
|
35
|
+
flags = response[offset, 4].unpack1('L<')
|
|
36
|
+
offset += 4
|
|
37
|
+
|
|
38
|
+
# tmp_sessions:flags.0?int
|
|
39
|
+
if (flags & (1 << 0)) != 0
|
|
40
|
+
offset += 4
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# otherwise_relogin_days:flags.1?int
|
|
44
|
+
if (flags & (1 << 1)) != 0
|
|
45
|
+
offset += 4
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# future_auth_token:flags.2?bytes
|
|
49
|
+
if (flags & (1 << 2)) != 0
|
|
50
|
+
first_byte = response[offset].unpack1('C')
|
|
51
|
+
|
|
52
|
+
if first_byte < 254
|
|
53
|
+
# Short format: 1 byte length + data + padding
|
|
54
|
+
token_len = first_byte
|
|
55
|
+
offset += 1 + token_len
|
|
56
|
+
padding = (4 - ((1 + token_len) % 4)) % 4
|
|
57
|
+
offset += padding
|
|
58
|
+
else
|
|
59
|
+
# Long format: 0xfe + 3 bytes length + data + padding
|
|
60
|
+
offset += 1
|
|
61
|
+
token_len = response[offset, 3].unpack('CCC').inject(0) {|sum, b| (sum << 8) + b}
|
|
62
|
+
offset += 3 + token_len
|
|
63
|
+
padding = (4 - ((4 + token_len) % 4)) % 4
|
|
64
|
+
offset += padding
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Parse User object
|
|
69
|
+
# user#20b1422 flags:# flags2:# id:long access_hash:flags.0?long ...
|
|
70
|
+
user_constructor = response[offset, 4].unpack1('L<')
|
|
71
|
+
offset += 4
|
|
72
|
+
|
|
73
|
+
user_flags = response[offset, 4].unpack1('L<')
|
|
74
|
+
offset += 4
|
|
75
|
+
|
|
76
|
+
user_flags2 = response[offset, 4].unpack1('L<')
|
|
77
|
+
offset += 4
|
|
78
|
+
|
|
79
|
+
# id:long (always present)
|
|
80
|
+
user_id = response[offset, 8].unpack1('Q<')
|
|
81
|
+
offset += 8
|
|
82
|
+
|
|
83
|
+
# access_hash:flags.0?long (conditional on flags.0)
|
|
84
|
+
access_hash = nil
|
|
85
|
+
if (user_flags & (1 << 0)) != 0
|
|
86
|
+
access_hash = response[offset, 8].unpack1('Q<')
|
|
87
|
+
offset += 8
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# We have what we need, skip the rest of User fields
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
authorization: true,
|
|
94
|
+
flags: flags,
|
|
95
|
+
sign_up_required: false,
|
|
96
|
+
user_id: user_id,
|
|
97
|
+
access_hash: access_hash
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
raise UnexpectedConstructorError.new(constructor)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../serializer'
|
|
4
|
+
require_relative '../../code_settings'
|
|
5
|
+
|
|
6
|
+
module MTProto
|
|
7
|
+
module Type
|
|
8
|
+
module RPC
|
|
9
|
+
module Auth
|
|
10
|
+
class SendCode
|
|
11
|
+
CONSTRUCTOR = 0xa677244f
|
|
12
|
+
|
|
13
|
+
def self.build(phone_number:, api_id:, api_hash:, code_settings: {})
|
|
14
|
+
raise ArgumentError, 'phone_number is required' if phone_number.nil? || phone_number.empty?
|
|
15
|
+
|
|
16
|
+
query = [CONSTRUCTOR].pack('L<')
|
|
17
|
+
query += Serializer.serialize_string(phone_number)
|
|
18
|
+
query += Serializer.serialize_int(api_id)
|
|
19
|
+
query += Serializer.serialize_string(api_hash)
|
|
20
|
+
query += CodeSettings.serialize(code_settings)
|
|
21
|
+
|
|
22
|
+
query
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../gzip_packed'
|
|
4
|
+
require_relative '../../rpc_error'
|
|
5
|
+
require_relative '../../sent_code'
|
|
6
|
+
|
|
7
|
+
module MTProto
|
|
8
|
+
module Type
|
|
9
|
+
module RPC
|
|
10
|
+
module Auth
|
|
11
|
+
class SentCode
|
|
12
|
+
def self.parse(response)
|
|
13
|
+
constructor = response[0, 4].unpack1('L<')
|
|
14
|
+
|
|
15
|
+
if constructor == Type::GzipPacked::CONSTRUCTOR
|
|
16
|
+
response = Type::GzipPacked.unpack(response)
|
|
17
|
+
constructor = response[0, 4].unpack1('L<')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
if constructor == Type::RpcError::CONSTRUCTOR
|
|
21
|
+
error = Type::RpcError.deserialize(response)
|
|
22
|
+
raise MTProto::RpcError.new(error.error_code, error.error_message)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
if constructor == Type::SentCode::CONSTRUCTOR
|
|
26
|
+
sent_code = Type::SentCode.deserialize(response)
|
|
27
|
+
sent_code.to_h
|
|
28
|
+
else
|
|
29
|
+
raise UnexpectedConstructorError.new(constructor)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../serializer'
|
|
4
|
+
|
|
5
|
+
module MTProto
|
|
6
|
+
module Type
|
|
7
|
+
module RPC
|
|
8
|
+
module Auth
|
|
9
|
+
class SignIn
|
|
10
|
+
CONSTRUCTOR = 0x8d52a951
|
|
11
|
+
|
|
12
|
+
def self.build(phone_number:, phone_code_hash:, phone_code:)
|
|
13
|
+
raise ArgumentError, 'phone_number is required' if phone_number.nil? || phone_number.empty?
|
|
14
|
+
raise ArgumentError, 'phone_code_hash is required' if phone_code_hash.nil? || phone_code_hash.empty?
|
|
15
|
+
raise ArgumentError, 'phone_code is required' if phone_code.nil? || phone_code.empty?
|
|
16
|
+
|
|
17
|
+
flags = 0
|
|
18
|
+
flags |= (1 << 0) # phone_code present
|
|
19
|
+
|
|
20
|
+
query = [CONSTRUCTOR].pack('L<')
|
|
21
|
+
query += Serializer.serialize_int(flags)
|
|
22
|
+
query += Serializer.serialize_string(phone_number)
|
|
23
|
+
query += Serializer.serialize_string(phone_code_hash)
|
|
24
|
+
query += Serializer.serialize_string(phone_code)
|
|
25
|
+
|
|
26
|
+
query
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|