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.
- checksums.yaml +4 -4
- data/data/tl-schema.json +42686 -0
- data/ext/aes_ige/extconf.rb +3 -9
- data/ext/factorization/extconf.rb +2 -0
- data/lib/mtproto/auth_key_generator.rb +68 -105
- data/lib/mtproto/binary.rb +21 -0
- data/lib/mtproto/client/api/check_password.rb +41 -0
- data/lib/mtproto/client/api/export_login_token.rb +27 -0
- data/lib/mtproto/client/api/get_dialogs.rb +21 -0
- data/lib/mtproto/client/api/get_history.rb +20 -0
- data/lib/mtproto/client/api/get_updates_difference.rb +21 -0
- data/lib/mtproto/client/api/get_updates_state.rb +14 -0
- data/lib/mtproto/client/api/get_users.rb +14 -0
- data/lib/mtproto/client/api/import_login_token.rb +23 -0
- data/lib/mtproto/client/api/send_code.rb +21 -0
- data/lib/mtproto/client/api/sign_in.rb +27 -0
- data/lib/mtproto/client/api.rb +36 -0
- data/lib/mtproto/client/rpc/response.rb +63 -0
- data/lib/mtproto/client/rpc.rb +60 -127
- data/lib/mtproto/client.rb +143 -32
- data/lib/mtproto/crypto/dh_key_exchange.rb +1 -2
- data/lib/mtproto/crypto/dh_validator.rb +17 -19
- data/lib/mtproto/crypto/factorization.rb +1 -1
- data/lib/mtproto/crypto/rsa_key.rb +2 -2
- data/lib/mtproto/crypto/srp.rb +117 -0
- data/lib/mtproto/delegate_methods.rb +11 -0
- data/lib/mtproto/errors.rb +8 -0
- data/lib/mtproto/message/message.rb +85 -0
- data/lib/mtproto/session.rb +1 -1
- data/lib/mtproto/tl/constructor_names.rb +2271 -0
- data/lib/mtproto/tl/constructors.rb +99 -0
- data/lib/mtproto/tl/object.rb +25 -0
- data/lib/mtproto/tl/objects/account_password.rb +69 -0
- data/lib/mtproto/tl/objects/authorization.rb +70 -0
- data/lib/mtproto/tl/objects/check_password.rb +43 -0
- data/lib/mtproto/tl/objects/client_dh_inner_data.rb +45 -0
- data/lib/mtproto/tl/objects/dh_gen_response.rb +46 -0
- data/lib/mtproto/tl/objects/dialogs.rb +453 -0
- data/lib/mtproto/tl/objects/export_login_token.rb +48 -0
- data/lib/mtproto/tl/objects/get_config.rb +13 -0
- data/lib/mtproto/tl/objects/get_dialogs.rb +51 -0
- data/lib/mtproto/tl/objects/get_difference.rb +34 -0
- data/lib/mtproto/tl/objects/get_history.rb +49 -0
- data/lib/mtproto/tl/objects/get_password.rb +13 -0
- data/lib/mtproto/tl/objects/get_state.rb +13 -0
- data/lib/mtproto/tl/objects/get_users.rb +16 -0
- data/lib/mtproto/{type → tl/objects}/gzip_packed.rb +6 -6
- data/lib/mtproto/tl/objects/help_config.rb +76 -0
- data/lib/mtproto/tl/objects/import_login_token.rb +37 -0
- data/lib/mtproto/tl/objects/init_connection.rb +57 -0
- data/lib/mtproto/tl/objects/invoke_with_layer.rb +20 -0
- data/lib/mtproto/tl/objects/login_token.rb +78 -0
- data/lib/mtproto/{type → tl/objects}/message.rb +3 -3
- data/lib/mtproto/tl/objects/messages.rb +162 -0
- data/lib/mtproto/{type → tl/objects}/msg_container.rb +1 -3
- data/lib/mtproto/{type → tl/objects}/new_session_created.rb +1 -3
- data/lib/mtproto/tl/objects/pq_inner_data.rb +66 -0
- data/lib/mtproto/tl/objects/req_dh_params.rb +63 -0
- data/lib/mtproto/tl/objects/req_pq_multi.rb +21 -0
- data/lib/mtproto/tl/objects/res_pq.rb +73 -0
- data/lib/mtproto/{type → tl/objects}/rpc_error.rb +1 -4
- data/lib/mtproto/tl/objects/send_code.rb +47 -0
- data/lib/mtproto/tl/objects/sent_code.rb +79 -0
- data/lib/mtproto/tl/objects/server_dh_inner_data.rb +74 -0
- data/lib/mtproto/tl/objects/server_dh_params.rb +53 -0
- data/lib/mtproto/tl/objects/set_client_dh_params.rb +46 -0
- data/lib/mtproto/tl/objects/sign_in.rb +45 -0
- data/lib/mtproto/tl/objects/update.rb +77 -0
- data/lib/mtproto/tl/objects/update_short.rb +20 -0
- data/lib/mtproto/tl/objects/update_short_message.rb +65 -0
- data/lib/mtproto/tl/objects/updates_difference.rb +152 -0
- data/lib/mtproto/tl/objects/updates_state.rb +35 -0
- data/lib/mtproto/tl/objects/users.rb +83 -0
- data/lib/mtproto/tl/schema.rb +102 -0
- data/lib/mtproto/transport/abridged_packet_codec.rb +35 -12
- data/lib/mtproto/transport/connection.rb +23 -0
- data/lib/mtproto/transport/errors.rb +11 -0
- data/lib/mtproto/transport/packet.rb +19 -0
- data/lib/mtproto/transport/tcp_connection.rb +57 -46
- data/lib/mtproto/updates_poller.rb +37 -33
- data/lib/mtproto/version.rb +1 -1
- data/lib/mtproto.rb +17 -27
- data/scripts/generate_constructors.rb +65 -0
- metadata +76 -61
- data/lib/mtproto/async/middleware/base.rb +0 -17
- data/lib/mtproto/async/middleware/flood_wait.rb +0 -42
- data/lib/mtproto/async/request.rb +0 -18
- data/lib/mtproto/async/request_queue.rb +0 -63
- data/lib/mtproto/async_client.rb +0 -201
- data/lib/mtproto/rpc/get_config.rb +0 -34
- data/lib/mtproto/rpc/get_contacts.rb +0 -29
- data/lib/mtproto/rpc/get_updates_difference.rb +0 -51
- data/lib/mtproto/rpc/get_updates_state.rb +0 -29
- data/lib/mtproto/rpc/get_users.rb +0 -29
- data/lib/mtproto/rpc/ping.rb +0 -33
- data/lib/mtproto/rpc/send_code.rb +0 -41
- data/lib/mtproto/rpc/send_message.rb +0 -47
- data/lib/mtproto/rpc/sign_in.rb +0 -48
- data/lib/mtproto/type/auth_key/dh_gen_response.rb +0 -37
- data/lib/mtproto/type/auth_key/req_dh_params.rb +0 -31
- data/lib/mtproto/type/auth_key/req_pq_multi.rb +0 -18
- data/lib/mtproto/type/auth_key/res_pq.rb +0 -62
- data/lib/mtproto/type/auth_key/server_dh_params.rb +0 -43
- data/lib/mtproto/type/auth_key/set_client_dh_params.rb +0 -25
- data/lib/mtproto/type/bad_msg_notification.rb +0 -46
- data/lib/mtproto/type/client_dh_inner_data.rb +0 -29
- data/lib/mtproto/type/code_settings.rb +0 -25
- data/lib/mtproto/type/config.rb +0 -124
- data/lib/mtproto/type/pq_inner_data.rb +0 -41
- data/lib/mtproto/type/rpc/auth/authorization.rb +0 -107
- data/lib/mtproto/type/rpc/auth/send_code.rb +0 -28
- data/lib/mtproto/type/rpc/auth/sent_code.rb +0 -36
- data/lib/mtproto/type/rpc/auth/sign_in.rb +0 -32
- data/lib/mtproto/type/rpc/contacts/contacts.rb +0 -155
- data/lib/mtproto/type/rpc/contacts/get_contacts.rb +0 -18
- data/lib/mtproto/type/rpc/help/config.rb +0 -35
- data/lib/mtproto/type/rpc/help/get_config.rb +0 -17
- data/lib/mtproto/type/rpc/init_connection.rb +0 -28
- data/lib/mtproto/type/rpc/invoke_with_layer.rb +0 -19
- data/lib/mtproto/type/rpc/messages/send_message.rb +0 -43
- data/lib/mtproto/type/rpc/messages/updates.rb +0 -87
- data/lib/mtproto/type/rpc/ping.rb +0 -18
- data/lib/mtproto/type/rpc/pong.rb +0 -46
- data/lib/mtproto/type/rpc/updates/difference.rb +0 -332
- data/lib/mtproto/type/rpc/updates/get_difference.rb +0 -42
- data/lib/mtproto/type/rpc/updates/get_state.rb +0 -17
- data/lib/mtproto/type/rpc/updates/state.rb +0 -59
- data/lib/mtproto/type/rpc/users/get_users.rb +0 -25
- data/lib/mtproto/type/rpc/users/users.rb +0 -99
- data/lib/mtproto/type/sent_code.rb +0 -128
- data/lib/mtproto/type/serializer.rb +0 -55
- data/lib/mtproto/type/server_dh_inner_data.rb +0 -85
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class ResPq
|
|
6
|
+
extend Binary
|
|
7
|
+
|
|
8
|
+
attr_reader :nonce, :server_nonce, :pq, :fingerprints
|
|
9
|
+
|
|
10
|
+
def self.parse(message)
|
|
11
|
+
data = message.body
|
|
12
|
+
constructor = b_u32(data[0, 4])
|
|
13
|
+
raise "Unexpected constructor: 0x#{constructor.to_s(16)}" unless constructor == Constructors::RES_PQ
|
|
14
|
+
|
|
15
|
+
offset = 4
|
|
16
|
+
|
|
17
|
+
nonce = data[offset, 16].pack('C*')
|
|
18
|
+
offset += 16
|
|
19
|
+
|
|
20
|
+
server_nonce = data[offset, 16].pack('C*')
|
|
21
|
+
offset += 16
|
|
22
|
+
|
|
23
|
+
pq_length_byte = data[offset]
|
|
24
|
+
offset += 1
|
|
25
|
+
|
|
26
|
+
pq_length = if pq_length_byte == 254
|
|
27
|
+
b_u32(data[offset, 3] + [0]) & 0xffffff
|
|
28
|
+
offset += 3
|
|
29
|
+
else
|
|
30
|
+
pq_length_byte
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
pq = data[offset, pq_length].pack('C*')
|
|
34
|
+
offset += pq_length
|
|
35
|
+
offset += padding_length(pq_length + 1)
|
|
36
|
+
|
|
37
|
+
vector_constructor = b_u32(data[offset, 4])
|
|
38
|
+
offset += 4
|
|
39
|
+
raise 'Expected vector constructor' unless vector_constructor == Constructors::VECTOR
|
|
40
|
+
|
|
41
|
+
fingerprints_count = b_u32(data[offset, 4])
|
|
42
|
+
offset += 4
|
|
43
|
+
|
|
44
|
+
fingerprints = []
|
|
45
|
+
fingerprints_count.times do
|
|
46
|
+
fingerprints << b_u64(data[offset, 8])
|
|
47
|
+
offset += 8
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
new(
|
|
51
|
+
nonce: nonce,
|
|
52
|
+
server_nonce: server_nonce,
|
|
53
|
+
pq: pq,
|
|
54
|
+
fingerprints: fingerprints
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.padding_length(length)
|
|
59
|
+
(4 - (length % 4)) % 4
|
|
60
|
+
end
|
|
61
|
+
private_class_method :padding_length
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def initialize(nonce:, server_nonce:, pq:, fingerprints:)
|
|
66
|
+
@nonce = nonce
|
|
67
|
+
@server_nonce = server_nonce
|
|
68
|
+
@pq = pq
|
|
69
|
+
@fingerprints = fingerprints
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MTProto
|
|
4
|
-
module
|
|
4
|
+
module TL
|
|
5
5
|
class RpcError
|
|
6
|
-
CONSTRUCTOR = 0x2144ca19
|
|
7
|
-
|
|
8
6
|
attr_reader :error_code, :error_message
|
|
9
7
|
|
|
10
8
|
def self.deserialize(data)
|
|
@@ -16,7 +14,6 @@ module MTProto
|
|
|
16
14
|
offset += 1
|
|
17
15
|
|
|
18
16
|
error_message = data[offset, message_length]
|
|
19
|
-
offset += message_length
|
|
20
17
|
|
|
21
18
|
new(error_code: error_code, error_message: error_message)
|
|
22
19
|
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class SendCode
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
attr_reader :phone_number, :api_id, :api_hash
|
|
9
|
+
|
|
10
|
+
def initialize(phone_number:, api_id:, api_hash:)
|
|
11
|
+
@phone_number = phone_number
|
|
12
|
+
@api_id = api_id
|
|
13
|
+
@api_hash = api_hash
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def body
|
|
17
|
+
u32_b(Constructors::AUTH_SEND_CODE) +
|
|
18
|
+
serialize_tl_string(@phone_number) +
|
|
19
|
+
u32_b(@api_id) +
|
|
20
|
+
serialize_tl_string(@api_hash) +
|
|
21
|
+
code_settings
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def code_settings
|
|
27
|
+
u32_b(Constructors::CODE_SETTINGS) + u32_b(0)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def serialize_tl_string(str)
|
|
31
|
+
bytes = str.encode('UTF-8').bytes
|
|
32
|
+
length = bytes.length
|
|
33
|
+
|
|
34
|
+
if length <= 253
|
|
35
|
+
[length] + bytes + padding(length + 1)
|
|
36
|
+
else
|
|
37
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def padding(current_length)
|
|
42
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
43
|
+
[0] * pad_length
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class SentCode
|
|
6
|
+
attr_reader :flags, :type, :phone_code_hash, :next_type, :timeout
|
|
7
|
+
|
|
8
|
+
def initialize(flags:, type:, phone_code_hash:, next_type: nil, timeout: nil)
|
|
9
|
+
@flags = flags
|
|
10
|
+
@type = type
|
|
11
|
+
@phone_code_hash = phone_code_hash
|
|
12
|
+
@next_type = next_type
|
|
13
|
+
@timeout = timeout
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.parse(data)
|
|
17
|
+
constructor = data[0, 4].unpack1('L<')
|
|
18
|
+
raise UnexpectedConstructorError, constructor unless constructor == Constructors::AUTH_SENT_CODE
|
|
19
|
+
|
|
20
|
+
offset = 4
|
|
21
|
+
flags = data[offset, 4].unpack1('L<')
|
|
22
|
+
offset += 4
|
|
23
|
+
|
|
24
|
+
type, offset = parse_sent_code_type(data, offset)
|
|
25
|
+
|
|
26
|
+
phone_code_hash, offset = read_tl_string(data, offset)
|
|
27
|
+
|
|
28
|
+
next_type = nil
|
|
29
|
+
next_type, offset = parse_code_type(data, offset) if flags.anybits?(1 << 1)
|
|
30
|
+
|
|
31
|
+
timeout = nil
|
|
32
|
+
timeout = data[offset, 4].unpack1('L<') if flags.anybits?(1 << 2)
|
|
33
|
+
|
|
34
|
+
new(flags: flags, type: type, phone_code_hash: phone_code_hash, next_type: next_type, timeout: timeout)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class << self
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def parse_sent_code_type(data, offset)
|
|
41
|
+
constructor = data[offset, 4].unpack1('L<')
|
|
42
|
+
offset += 4
|
|
43
|
+
|
|
44
|
+
case constructor
|
|
45
|
+
when Constructors::AUTH_SENT_CODE_TYPE_APP,
|
|
46
|
+
Constructors::AUTH_SENT_CODE_TYPE_SMS,
|
|
47
|
+
Constructors::AUTH_SENT_CODE_TYPE_CALL
|
|
48
|
+
length = data[offset, 4].unpack1('L<')
|
|
49
|
+
offset += 4
|
|
50
|
+
[{ length: length }, offset]
|
|
51
|
+
else
|
|
52
|
+
[{}, offset]
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def parse_code_type(data, offset)
|
|
57
|
+
constructor = data[offset, 4].unpack1('L<')
|
|
58
|
+
offset += 4
|
|
59
|
+
[constructor, offset]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def read_tl_string(data, offset)
|
|
63
|
+
first_byte = data.getbyte(offset)
|
|
64
|
+
if first_byte == 254
|
|
65
|
+
len = data.getbyte(offset + 1) |
|
|
66
|
+
(data.getbyte(offset + 2) << 8) |
|
|
67
|
+
(data.getbyte(offset + 3) << 16)
|
|
68
|
+
total = 4 + len
|
|
69
|
+
else
|
|
70
|
+
len = first_byte
|
|
71
|
+
total = 1 + len
|
|
72
|
+
end
|
|
73
|
+
padding = (4 - (total % 4)) % 4
|
|
74
|
+
[data[offset + (total - len), len], offset + total + padding]
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class ServerDHInnerData
|
|
6
|
+
attr_reader :nonce, :server_nonce, :g, :dh_prime, :g_a, :server_time
|
|
7
|
+
|
|
8
|
+
def self.parse(bytes)
|
|
9
|
+
constructor = bytes[0, 4].unpack1('L<')
|
|
10
|
+
unless constructor == Constructors::SERVER_DH_INNER_DATA
|
|
11
|
+
raise "Unexpected constructor: 0x#{constructor.to_s(16)}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
offset = 4
|
|
15
|
+
|
|
16
|
+
nonce = bytes[offset, 16]
|
|
17
|
+
offset += 16
|
|
18
|
+
|
|
19
|
+
server_nonce = bytes[offset, 16]
|
|
20
|
+
offset += 16
|
|
21
|
+
|
|
22
|
+
g = bytes[offset, 4].unpack1('L<')
|
|
23
|
+
offset += 4
|
|
24
|
+
|
|
25
|
+
dh_prime, offset = read_tl_bytes(bytes, offset)
|
|
26
|
+
g_a, offset = read_tl_bytes(bytes, offset)
|
|
27
|
+
|
|
28
|
+
server_time = bytes[offset, 4].unpack1('L<')
|
|
29
|
+
|
|
30
|
+
new(
|
|
31
|
+
nonce: nonce,
|
|
32
|
+
server_nonce: server_nonce,
|
|
33
|
+
g: g,
|
|
34
|
+
dh_prime: dh_prime,
|
|
35
|
+
g_a: g_a,
|
|
36
|
+
server_time: server_time
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.read_tl_bytes(bytes, offset)
|
|
41
|
+
length_byte = bytes[offset].ord
|
|
42
|
+
offset += 1
|
|
43
|
+
|
|
44
|
+
if length_byte == 254
|
|
45
|
+
length_bytes = bytes[offset, 3].bytes
|
|
46
|
+
length = length_bytes[0] | (length_bytes[1] << 8) | (length_bytes[2] << 16)
|
|
47
|
+
offset += 3
|
|
48
|
+
header_size = 4
|
|
49
|
+
else
|
|
50
|
+
length = length_byte
|
|
51
|
+
header_size = 1
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
value = bytes[offset, length]
|
|
55
|
+
offset += length
|
|
56
|
+
offset += (4 - ((header_size + length) % 4)) % 4
|
|
57
|
+
|
|
58
|
+
[value, offset]
|
|
59
|
+
end
|
|
60
|
+
private_class_method :read_tl_bytes
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def initialize(nonce:, server_nonce:, g:, dh_prime:, g_a:, server_time:)
|
|
65
|
+
@nonce = nonce
|
|
66
|
+
@server_nonce = server_nonce
|
|
67
|
+
@g = g
|
|
68
|
+
@dh_prime = dh_prime
|
|
69
|
+
@g_a = g_a
|
|
70
|
+
@server_time = server_time
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class ServerDHParams
|
|
6
|
+
extend Binary
|
|
7
|
+
|
|
8
|
+
attr_reader :nonce, :server_nonce, :encrypted_answer
|
|
9
|
+
|
|
10
|
+
def self.parse(message)
|
|
11
|
+
data = message.body
|
|
12
|
+
constructor = b_u32(data[0, 4])
|
|
13
|
+
unless constructor == Constructors::SERVER_DH_PARAMS_OK
|
|
14
|
+
raise "Unexpected constructor: 0x#{constructor.to_s(16)}"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
offset = 4
|
|
18
|
+
|
|
19
|
+
nonce = data[offset, 16].pack('C*')
|
|
20
|
+
offset += 16
|
|
21
|
+
|
|
22
|
+
server_nonce = data[offset, 16].pack('C*')
|
|
23
|
+
offset += 16
|
|
24
|
+
|
|
25
|
+
length_byte = data[offset]
|
|
26
|
+
offset += 1
|
|
27
|
+
|
|
28
|
+
if length_byte == 254
|
|
29
|
+
encrypted_answer_length = data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16)
|
|
30
|
+
offset += 3
|
|
31
|
+
else
|
|
32
|
+
encrypted_answer_length = length_byte
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
encrypted_answer = data[offset, encrypted_answer_length].pack('C*')
|
|
36
|
+
|
|
37
|
+
new(
|
|
38
|
+
nonce: nonce,
|
|
39
|
+
server_nonce: server_nonce,
|
|
40
|
+
encrypted_answer: encrypted_answer
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def initialize(nonce:, server_nonce:, encrypted_answer:)
|
|
47
|
+
@nonce = nonce
|
|
48
|
+
@server_nonce = server_nonce
|
|
49
|
+
@encrypted_answer = encrypted_answer
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class SetClientDHParams
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
attr_reader :nonce, :server_nonce, :encrypted_data
|
|
9
|
+
|
|
10
|
+
def initialize(nonce:, server_nonce:, encrypted_data:)
|
|
11
|
+
raise ArgumentError, 'Nonce must be 16 bytes' unless nonce.bytesize == 16
|
|
12
|
+
raise ArgumentError, 'Server nonce must be 16 bytes' unless server_nonce.bytesize == 16
|
|
13
|
+
|
|
14
|
+
@nonce = nonce
|
|
15
|
+
@server_nonce = server_nonce
|
|
16
|
+
@encrypted_data = encrypted_data
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def body
|
|
20
|
+
result = u32_b(Constructors::SET_CLIENT_DH_PARAMS)
|
|
21
|
+
result += @nonce.bytes
|
|
22
|
+
result += @server_nonce.bytes
|
|
23
|
+
result += serialize_tl_bytes(@encrypted_data.bytes)
|
|
24
|
+
|
|
25
|
+
result
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def serialize_tl_bytes(bytes)
|
|
31
|
+
length = bytes.length
|
|
32
|
+
|
|
33
|
+
if length <= 253
|
|
34
|
+
[length] + bytes + padding(length + 1)
|
|
35
|
+
else
|
|
36
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def padding(current_length)
|
|
41
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
42
|
+
[0] * pad_length
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class SignIn
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
attr_reader :phone_number, :phone_code_hash, :phone_code
|
|
9
|
+
|
|
10
|
+
def initialize(phone_number:, phone_code_hash:, phone_code:)
|
|
11
|
+
@phone_number = phone_number
|
|
12
|
+
@phone_code_hash = phone_code_hash
|
|
13
|
+
@phone_code = phone_code
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def body
|
|
17
|
+
flags = 1 << 0
|
|
18
|
+
|
|
19
|
+
u32_b(Constructors::AUTH_SIGN_IN) +
|
|
20
|
+
u32_b(flags) +
|
|
21
|
+
serialize_tl_string(@phone_number) +
|
|
22
|
+
serialize_tl_string(@phone_code_hash) +
|
|
23
|
+
serialize_tl_string(@phone_code)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def serialize_tl_string(str)
|
|
29
|
+
bytes = str.encode('UTF-8').bytes
|
|
30
|
+
length = bytes.length
|
|
31
|
+
|
|
32
|
+
if length <= 253
|
|
33
|
+
[length] + bytes + padding(length + 1)
|
|
34
|
+
else
|
|
35
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def padding(current_length)
|
|
40
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
41
|
+
[0] * pad_length
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class Update
|
|
6
|
+
attr_reader :type, :text
|
|
7
|
+
|
|
8
|
+
def initialize(type, text: nil)
|
|
9
|
+
@type = type
|
|
10
|
+
@text = text
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.parse(bytes)
|
|
14
|
+
constructor_id = bytes[0, 4].unpack1('L<')
|
|
15
|
+
type = type_name(constructor_id)
|
|
16
|
+
|
|
17
|
+
case constructor_id
|
|
18
|
+
when Constructors::UPDATE_NEW_MESSAGE
|
|
19
|
+
text = extract_new_message_text(bytes)
|
|
20
|
+
new(type, text: text)
|
|
21
|
+
else
|
|
22
|
+
new(type)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def type_name(constructor_id)
|
|
30
|
+
name = ConstructorNames::NAMES.fetch(constructor_id)
|
|
31
|
+
name.sub(/^update/, '')
|
|
32
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
33
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
34
|
+
.downcase
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def extract_new_message_text(bytes)
|
|
38
|
+
offset = 4 # skip updateNewMessage constructor
|
|
39
|
+
|
|
40
|
+
msg_constructor = bytes[offset, 4].unpack1('L<')
|
|
41
|
+
return nil unless msg_constructor == Constructors::MESSAGE
|
|
42
|
+
|
|
43
|
+
offset += 4
|
|
44
|
+
flags = bytes[offset, 4].unpack1('L<')
|
|
45
|
+
offset += 4
|
|
46
|
+
flags2 = bytes[offset, 4].unpack1('L<')
|
|
47
|
+
offset += 4
|
|
48
|
+
offset += 4 # id
|
|
49
|
+
|
|
50
|
+
offset += 12 if flags & (1 << 8) != 0 # from_id: Peer
|
|
51
|
+
offset += 12 # peer_id: Peer
|
|
52
|
+
offset += 12 if flags & (1 << 28) != 0 # saved_peer_id: Peer
|
|
53
|
+
return nil if flags & (1 << 2) != 0 # fwd_from: variable length
|
|
54
|
+
|
|
55
|
+
offset += 8 if flags & (1 << 11) != 0 # via_bot_id: long
|
|
56
|
+
offset += 8 if flags2 & 1 != 0 # via_business_bot_id: long
|
|
57
|
+
return nil if flags & (1 << 3) != 0 # reply_to: variable length
|
|
58
|
+
|
|
59
|
+
offset += 4 # date
|
|
60
|
+
read_tl_string(bytes, offset)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def read_tl_string(bytes, offset)
|
|
64
|
+
first_byte = bytes.getbyte(offset)
|
|
65
|
+
if first_byte == 254
|
|
66
|
+
len = bytes.getbyte(offset + 1) |
|
|
67
|
+
(bytes.getbyte(offset + 2) << 8) |
|
|
68
|
+
(bytes.getbyte(offset + 3) << 16)
|
|
69
|
+
bytes[offset + 4, len]
|
|
70
|
+
else
|
|
71
|
+
bytes[offset + 1, first_byte]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class UpdateShort
|
|
6
|
+
attr_reader :update, :date
|
|
7
|
+
|
|
8
|
+
def initialize(update, date)
|
|
9
|
+
@update = update
|
|
10
|
+
@date = date
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.parse(bytes)
|
|
14
|
+
date = bytes[-4, 4].unpack1('l<')
|
|
15
|
+
update = Update.parse(bytes[4...-4])
|
|
16
|
+
new(update, date)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class UpdateShortMessage
|
|
6
|
+
attr_reader :flags, :id, :user_id, :text, :pts, :pts_count, :date
|
|
7
|
+
|
|
8
|
+
def initialize(flags:, id:, user_id:, text:, pts:, pts_count:, date:)
|
|
9
|
+
@flags = flags
|
|
10
|
+
@id = id
|
|
11
|
+
@user_id = user_id
|
|
12
|
+
@text = text
|
|
13
|
+
@pts = pts
|
|
14
|
+
@pts_count = pts_count
|
|
15
|
+
@date = date
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def out?
|
|
19
|
+
flags & (1 << 1) != 0
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def mentioned?
|
|
23
|
+
flags & (1 << 4) != 0
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.parse(bytes)
|
|
27
|
+
offset = 4 # skip constructor
|
|
28
|
+
flags = bytes[offset, 4].unpack1('L<')
|
|
29
|
+
offset += 4
|
|
30
|
+
id = bytes[offset, 4].unpack1('l<')
|
|
31
|
+
offset += 4
|
|
32
|
+
user_id = bytes[offset, 8].unpack1('q<')
|
|
33
|
+
offset += 8
|
|
34
|
+
text, offset = read_tl_string(bytes, offset)
|
|
35
|
+
pts = bytes[offset, 4].unpack1('l<')
|
|
36
|
+
offset += 4
|
|
37
|
+
pts_count = bytes[offset, 4].unpack1('l<')
|
|
38
|
+
offset += 4
|
|
39
|
+
date = bytes[offset, 4].unpack1('l<')
|
|
40
|
+
|
|
41
|
+
new(flags: flags, id: id, user_id: user_id, text: text,
|
|
42
|
+
pts: pts, pts_count: pts_count, date: date)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class << self
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def read_tl_string(bytes, offset)
|
|
49
|
+
first_byte = bytes.getbyte(offset)
|
|
50
|
+
if first_byte == 254
|
|
51
|
+
len = bytes.getbyte(offset + 1) |
|
|
52
|
+
(bytes.getbyte(offset + 2) << 8) |
|
|
53
|
+
(bytes.getbyte(offset + 3) << 16)
|
|
54
|
+
total = 4 + len
|
|
55
|
+
else
|
|
56
|
+
len = first_byte
|
|
57
|
+
total = 1 + len
|
|
58
|
+
end
|
|
59
|
+
padding = (4 - (total % 4)) % 4
|
|
60
|
+
[bytes[offset + (total - len), len], offset + total + padding]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|