mtproto 0.0.7 → 0.0.9

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +4 -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 +66 -103
  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_updates_difference.rb +21 -0
  10. data/lib/mtproto/client/api/get_updates_state.rb +14 -0
  11. data/lib/mtproto/client/api/get_users.rb +14 -0
  12. data/lib/mtproto/client/api/import_login_token.rb +23 -0
  13. data/lib/mtproto/client/api/send_code.rb +21 -0
  14. data/lib/mtproto/client/api/sign_in.rb +27 -0
  15. data/lib/mtproto/client/api.rb +28 -0
  16. data/lib/mtproto/client/rpc/response.rb +63 -0
  17. data/lib/mtproto/client/rpc.rb +67 -107
  18. data/lib/mtproto/client.rb +176 -31
  19. data/lib/mtproto/crypto/dh_key_exchange.rb +1 -2
  20. data/lib/mtproto/crypto/dh_validator.rb +17 -19
  21. data/lib/mtproto/crypto/factorization.rb +1 -1
  22. data/lib/mtproto/crypto/rsa_key.rb +2 -2
  23. data/lib/mtproto/crypto/srp.rb +117 -0
  24. data/lib/mtproto/delegate_methods.rb +11 -0
  25. data/lib/mtproto/message/message.rb +85 -0
  26. data/lib/mtproto/session.rb +1 -1
  27. data/lib/mtproto/tl/constructors.rb +2269 -0
  28. data/lib/mtproto/tl/object.rb +25 -0
  29. data/lib/mtproto/tl/objects/account_password.rb +72 -0
  30. data/lib/mtproto/tl/objects/authorization.rb +73 -0
  31. data/lib/mtproto/tl/objects/check_password.rb +46 -0
  32. data/lib/mtproto/tl/objects/client_dh_inner_data.rb +47 -0
  33. data/lib/mtproto/tl/objects/dh_gen_response.rb +50 -0
  34. data/lib/mtproto/tl/objects/export_login_token.rb +51 -0
  35. data/lib/mtproto/tl/objects/get_config.rb +15 -0
  36. data/lib/mtproto/tl/objects/get_difference.rb +36 -0
  37. data/lib/mtproto/tl/objects/get_password.rb +15 -0
  38. data/lib/mtproto/tl/objects/get_state.rb +15 -0
  39. data/lib/mtproto/tl/objects/get_users.rb +20 -0
  40. data/lib/mtproto/tl/objects/help_config.rb +77 -0
  41. data/lib/mtproto/tl/objects/import_login_token.rb +39 -0
  42. data/lib/mtproto/tl/objects/init_connection.rb +59 -0
  43. data/lib/mtproto/tl/objects/invoke_with_layer.rb +22 -0
  44. data/lib/mtproto/tl/objects/login_token.rb +82 -0
  45. data/lib/mtproto/tl/objects/pq_inner_data.rb +69 -0
  46. data/lib/mtproto/tl/objects/req_dh_params.rb +65 -0
  47. data/lib/mtproto/tl/objects/req_pq_multi.rb +23 -0
  48. data/lib/mtproto/tl/objects/res_pq.rb +75 -0
  49. data/lib/mtproto/tl/objects/send_code.rb +50 -0
  50. data/lib/mtproto/tl/objects/sent_code.rb +79 -0
  51. data/lib/mtproto/tl/objects/server_dh_inner_data.rb +74 -0
  52. data/lib/mtproto/tl/objects/server_dh_params.rb +53 -0
  53. data/lib/mtproto/tl/objects/set_client_dh_params.rb +48 -0
  54. data/lib/mtproto/tl/objects/sign_in.rb +47 -0
  55. data/lib/mtproto/tl/objects/update.rb +80 -0
  56. data/lib/mtproto/tl/objects/update_short.rb +22 -0
  57. data/lib/mtproto/tl/objects/update_short_message.rb +67 -0
  58. data/lib/mtproto/tl/objects/updates_difference.rb +157 -0
  59. data/lib/mtproto/tl/objects/updates_state.rb +37 -0
  60. data/lib/mtproto/tl/objects/users.rb +86 -0
  61. data/lib/mtproto/transport/abridged_packet_codec.rb +35 -12
  62. data/lib/mtproto/transport/connection.rb +23 -0
  63. data/lib/mtproto/transport/errors.rb +11 -0
  64. data/lib/mtproto/transport/packet.rb +19 -0
  65. data/lib/mtproto/transport/tcp_connection.rb +57 -46
  66. data/lib/mtproto/{tl → type}/bad_msg_notification.rb +11 -11
  67. data/lib/mtproto/{tl → type}/client_dh_inner_data.rb +1 -1
  68. data/lib/mtproto/{tl → type}/gzip_packed.rb +6 -4
  69. data/lib/mtproto/{tl → type}/message.rb +3 -3
  70. data/lib/mtproto/{tl → type}/msg_container.rb +1 -1
  71. data/lib/mtproto/{tl → type}/new_session_created.rb +1 -1
  72. data/lib/mtproto/{tl/p_q_inner_data.rb → type/pq_inner_data.rb} +1 -1
  73. data/lib/mtproto/{tl → type}/rpc_error.rb +1 -2
  74. data/lib/mtproto/{tl → type}/serializer.rb +1 -1
  75. data/lib/mtproto/{tl → type}/server_dh_inner_data.rb +1 -1
  76. data/lib/mtproto/updates_poller.rb +37 -33
  77. data/lib/mtproto/version.rb +1 -1
  78. data/lib/mtproto.rb +21 -22
  79. data/scripts/generate_constructors.rb +65 -0
  80. metadata +80 -49
  81. data/lib/mtproto/rpc/get_config.rb +0 -37
  82. data/lib/mtproto/rpc/get_contacts.rb +0 -22
  83. data/lib/mtproto/rpc/get_updates_difference.rb +0 -33
  84. data/lib/mtproto/rpc/get_updates_state.rb +0 -22
  85. data/lib/mtproto/rpc/get_users.rb +0 -22
  86. data/lib/mtproto/rpc/ping.rb +0 -26
  87. data/lib/mtproto/rpc/send_code.rb +0 -44
  88. data/lib/mtproto/rpc/send_message.rb +0 -31
  89. data/lib/mtproto/rpc/sign_in.rb +0 -52
  90. data/lib/mtproto/tl/auth_key/dh_gen_response.rb +0 -37
  91. data/lib/mtproto/tl/auth_key/req_dh_params.rb +0 -31
  92. data/lib/mtproto/tl/auth_key/req_pq_multi.rb +0 -18
  93. data/lib/mtproto/tl/auth_key/res_pq.rb +0 -62
  94. data/lib/mtproto/tl/auth_key/server_dh_params.rb +0 -43
  95. data/lib/mtproto/tl/auth_key/set_client_dh_params.rb +0 -25
  96. data/lib/mtproto/tl/code_settings.rb +0 -25
  97. data/lib/mtproto/tl/config.rb +0 -124
  98. data/lib/mtproto/tl/method_builder.rb +0 -29
  99. data/lib/mtproto/tl/rpc/auth/authorization.rb +0 -107
  100. data/lib/mtproto/tl/rpc/auth/send_code.rb +0 -28
  101. data/lib/mtproto/tl/rpc/auth/sent_code.rb +0 -36
  102. data/lib/mtproto/tl/rpc/auth/sign_in.rb +0 -32
  103. data/lib/mtproto/tl/rpc/contacts/contacts.rb +0 -155
  104. data/lib/mtproto/tl/rpc/contacts/get_contacts.rb +0 -18
  105. data/lib/mtproto/tl/rpc/help/config.rb +0 -35
  106. data/lib/mtproto/tl/rpc/help/get_config.rb +0 -17
  107. data/lib/mtproto/tl/rpc/messages/send_message.rb +0 -43
  108. data/lib/mtproto/tl/rpc/messages/updates.rb +0 -87
  109. data/lib/mtproto/tl/rpc/ping.rb +0 -18
  110. data/lib/mtproto/tl/rpc/pong.rb +0 -46
  111. data/lib/mtproto/tl/rpc/updates/difference.rb +0 -332
  112. data/lib/mtproto/tl/rpc/updates/get_difference.rb +0 -42
  113. data/lib/mtproto/tl/rpc/updates/get_state.rb +0 -17
  114. data/lib/mtproto/tl/rpc/updates/state.rb +0 -59
  115. data/lib/mtproto/tl/rpc/users/get_users.rb +0 -25
  116. data/lib/mtproto/tl/rpc/users/users.rb +0 -99
  117. data/lib/mtproto/tl/sent_code.rb +0 -128
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class Object
6
+ extend Binary
7
+
8
+ attr_reader :constructor, :payload
9
+
10
+ def initialize(constructor, payload)
11
+ @constructor = constructor
12
+ @payload = payload
13
+ end
14
+
15
+ def self.parse(message)
16
+ body = message.body
17
+ constructor_id = b_u32(body[0, 4])
18
+ constructor = Constructors::NAMES.fetch(constructor_id)
19
+ payload = body[4..]
20
+
21
+ new(constructor, payload)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class AccountPassword
6
+ CONSTRUCTOR = 0x957b50fb
7
+ ALGO_SHA256_MOD_POW = 0x3a912d4a
8
+
9
+ attr_reader :has_password, :current_algo, :srp_b, :srp_id
10
+
11
+ def initialize(has_password:, current_algo: nil, srp_b: nil, srp_id: nil)
12
+ @has_password = has_password
13
+ @current_algo = current_algo
14
+ @srp_b = srp_b
15
+ @srp_id = srp_id
16
+ end
17
+
18
+ def self.parse(data)
19
+ constructor = data[0, 4].unpack1('L<')
20
+ raise UnexpectedConstructorError, constructor unless constructor == CONSTRUCTOR
21
+
22
+ offset = 4
23
+ flags = data[offset, 4].unpack1('L<')
24
+ offset += 4
25
+
26
+ has_password = flags.anybits?(1 << 2)
27
+
28
+ return new(has_password: false) unless has_password
29
+
30
+ algo_constructor = data[offset, 4].unpack1('L<')
31
+ offset += 4
32
+
33
+ current_algo = nil
34
+ if algo_constructor == ALGO_SHA256_MOD_POW
35
+ salt1, offset = read_tl_bytes(data, offset)
36
+ salt2, offset = read_tl_bytes(data, offset)
37
+ g = data[offset, 4].unpack1('l<')
38
+ offset += 4
39
+ p, offset = read_tl_bytes(data, offset)
40
+
41
+ current_algo = { salt1: salt1, salt2: salt2, g: g, p: p }
42
+ end
43
+
44
+ srp_b, offset = read_tl_bytes(data, offset)
45
+ srp_id = data[offset, 8].unpack1('Q<')
46
+
47
+ new(has_password: true, current_algo: current_algo, srp_b: srp_b, srp_id: srp_id)
48
+ end
49
+
50
+ class << self
51
+ private
52
+
53
+ def read_tl_bytes(data, offset)
54
+ first_byte = data.getbyte(offset)
55
+ if first_byte < 254
56
+ len = first_byte
57
+ bytes = data[offset + 1, len]
58
+ total = 1 + len
59
+ else
60
+ len = data.getbyte(offset + 1) |
61
+ (data.getbyte(offset + 2) << 8) |
62
+ (data.getbyte(offset + 3) << 16)
63
+ bytes = data[offset + 4, len]
64
+ total = 4 + len
65
+ end
66
+ padding = (4 - (total % 4)) % 4
67
+ [bytes, offset + total + padding]
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class Authorization
6
+ CONSTRUCTOR = 0x2ea2c0d4
7
+ CONSTRUCTOR_SIGN_UP_REQUIRED = 0x44747e9a
8
+
9
+ attr_reader :user_id, :access_hash, :flags, :sign_up_required
10
+
11
+ def initialize(user_id: nil, access_hash: nil, flags: 0, sign_up_required: false)
12
+ @user_id = user_id
13
+ @access_hash = access_hash
14
+ @flags = flags
15
+ @sign_up_required = sign_up_required
16
+ end
17
+
18
+ def authorization?
19
+ !@sign_up_required && @user_id
20
+ end
21
+
22
+ def self.parse(data)
23
+ constructor = data[0, 4].unpack1('L<')
24
+
25
+ return new(sign_up_required: true) if constructor == CONSTRUCTOR_SIGN_UP_REQUIRED
26
+ raise UnexpectedConstructorError, constructor unless constructor == CONSTRUCTOR
27
+
28
+ offset = 4
29
+
30
+ flags = data[offset, 4].unpack1('L<')
31
+ offset += 4
32
+
33
+ offset += 4 if flags.anybits?(1 << 0) # tmp_sessions
34
+ offset += 4 if flags.anybits?(1 << 1) # otherwise_relogin_days
35
+
36
+ offset = skip_tl_bytes(data, offset) if flags.anybits?(1 << 2) # future_auth_token
37
+
38
+ # user#20b1422 flags:# flags2:# id:long access_hash:flags.0?long ...
39
+ offset += 4 # user constructor
40
+
41
+ user_flags = data[offset, 4].unpack1('L<')
42
+ offset += 4
43
+
44
+ offset += 4 # flags2
45
+
46
+ user_id = data[offset, 8].unpack1('Q<')
47
+ offset += 8
48
+
49
+ access_hash = nil
50
+ access_hash = data[offset, 8].unpack1('Q<') if user_flags.anybits?(1 << 0)
51
+
52
+ new(user_id: user_id, access_hash: access_hash, flags: flags)
53
+ end
54
+
55
+ class << self
56
+ private
57
+
58
+ def skip_tl_bytes(data, offset)
59
+ first_byte = data.getbyte(offset)
60
+ if first_byte < 254
61
+ total = 1 + first_byte
62
+ else
63
+ len = data.getbyte(offset + 1) |
64
+ (data.getbyte(offset + 2) << 8) |
65
+ (data.getbyte(offset + 3) << 16)
66
+ total = 4 + len
67
+ end
68
+ offset + total + ((4 - (total % 4)) % 4)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class CheckPassword
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0xd18b4d16
9
+ INPUT_CHECK_PASSWORD_SRP = 0xd27ff082
10
+
11
+ attr_reader :srp_id, :a, :m1
12
+
13
+ def initialize(srp_id:, a:, m1:)
14
+ @srp_id = srp_id
15
+ @a = a
16
+ @m1 = m1
17
+ end
18
+
19
+ def body
20
+ u32_b(CONSTRUCTOR) +
21
+ u32_b(INPUT_CHECK_PASSWORD_SRP) +
22
+ u64_b(@srp_id) +
23
+ serialize_tl_bytes(@a) +
24
+ serialize_tl_bytes(@m1)
25
+ end
26
+
27
+ private
28
+
29
+ def serialize_tl_bytes(data)
30
+ bytes = data.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,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class ClientDHInnerData
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0x6643b654
9
+
10
+ attr_reader :nonce, :server_nonce, :retry_id, :g_b
11
+
12
+ def initialize(nonce:, server_nonce:, retry_id:, g_b:)
13
+ @nonce = nonce
14
+ @server_nonce = server_nonce
15
+ @retry_id = retry_id
16
+ @g_b = g_b
17
+ end
18
+
19
+ def body
20
+ result = u32_b(CONSTRUCTOR)
21
+ result += @nonce.bytes
22
+ result += @server_nonce.bytes
23
+ result += u64_b(@retry_id)
24
+ result += serialize_tl_bytes(@g_b.bytes)
25
+
26
+ result
27
+ end
28
+
29
+ private
30
+
31
+ def serialize_tl_bytes(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,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class DHGenResponse
6
+ extend Binary
7
+
8
+ CONSTRUCTOR_OK = 0x3bcbf734
9
+ CONSTRUCTOR_RETRY = 0x46dc1fb9
10
+ CONSTRUCTOR_FAIL = 0xa69dae02
11
+
12
+ attr_reader :status, :nonce, :server_nonce, :new_nonce_hash
13
+
14
+ def self.parse(message)
15
+ data = message.body
16
+ constructor = b_u32(data[0, 4])
17
+
18
+ status = case constructor
19
+ when CONSTRUCTOR_OK then :ok
20
+ when CONSTRUCTOR_RETRY then :retry
21
+ when CONSTRUCTOR_FAIL then :fail
22
+ else raise "Unexpected constructor: 0x#{constructor.to_s(16)}"
23
+ end
24
+
25
+ offset = 4
26
+ nonce = data[offset, 16].pack('C*')
27
+ offset += 16
28
+ server_nonce = data[offset, 16].pack('C*')
29
+ offset += 16
30
+ new_nonce_hash = data[offset, 16].pack('C*')
31
+
32
+ new(
33
+ status: status,
34
+ nonce: nonce,
35
+ server_nonce: server_nonce,
36
+ new_nonce_hash: new_nonce_hash
37
+ )
38
+ end
39
+
40
+ private
41
+
42
+ def initialize(status:, nonce:, server_nonce:, new_nonce_hash:)
43
+ @status = status
44
+ @nonce = nonce
45
+ @server_nonce = server_nonce
46
+ @new_nonce_hash = new_nonce_hash
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class ExportLoginToken
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0xb7e085fe
9
+ VECTOR_CONSTRUCTOR = 0x1cb5c415
10
+
11
+ attr_reader :api_id, :api_hash, :except_ids
12
+
13
+ def initialize(api_id:, api_hash:, except_ids: [])
14
+ @api_id = api_id
15
+ @api_hash = api_hash
16
+ @except_ids = except_ids
17
+ end
18
+
19
+ def body
20
+ u32_b(CONSTRUCTOR) +
21
+ u32_b(@api_id) +
22
+ serialize_tl_string(@api_hash) +
23
+ serialize_vector_long(@except_ids)
24
+ end
25
+
26
+ private
27
+
28
+ def serialize_vector_long(ids)
29
+ result = u32_b(VECTOR_CONSTRUCTOR) + u32_b(ids.length)
30
+ ids.each { |id| result += u64_b(id) }
31
+ result
32
+ end
33
+
34
+ def serialize_tl_string(str)
35
+ bytes = str.encode('UTF-8').bytes
36
+ length = bytes.length
37
+
38
+ if length <= 253
39
+ [length] + bytes + padding(length + 1)
40
+ else
41
+ [254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
42
+ end
43
+ end
44
+
45
+ def padding(current_length)
46
+ pad_length = (4 - (current_length % 4)) % 4
47
+ [0] * pad_length
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class GetConfig
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0xc4f9186b
9
+
10
+ def body
11
+ u32_b(CONSTRUCTOR)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class GetDifference
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0x19c2f763
9
+
10
+ attr_reader :pts, :date, :qts, :pts_limit, :pts_total_limit, :qts_limit
11
+
12
+ def initialize(pts:, date:, qts:, pts_limit: nil, pts_total_limit: nil, qts_limit: nil)
13
+ @pts = pts
14
+ @date = date
15
+ @qts = qts
16
+ @pts_limit = pts_limit
17
+ @pts_total_limit = pts_total_limit
18
+ @qts_limit = qts_limit
19
+ end
20
+
21
+ def body
22
+ flags = 0
23
+ flags |= (1 << 0) if @pts_limit
24
+ flags |= (1 << 1) if @pts_total_limit
25
+ flags |= (1 << 2) if @qts_limit
26
+
27
+ result = u32_b(CONSTRUCTOR) + u32_b(flags) + u32_b(@pts)
28
+ result += u32_b(@pts_limit) if @pts_limit
29
+ result += u32_b(@pts_total_limit) if @pts_total_limit
30
+ result += u32_b(@date) + u32_b(@qts)
31
+ result += u32_b(@qts_limit) if @qts_limit
32
+ result
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class GetPassword
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0x548a30f5
9
+
10
+ def body
11
+ u32_b(CONSTRUCTOR)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class GetState
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0xedd4882a
9
+
10
+ def body
11
+ u32_b(CONSTRUCTOR)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class GetUsers
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0x0d91a548
9
+ VECTOR_CONSTRUCTOR = 0x1cb5c415
10
+ INPUT_USER_SELF = 0xf7c1b13f
11
+
12
+ def body
13
+ u32_b(CONSTRUCTOR) +
14
+ u32_b(VECTOR_CONSTRUCTOR) +
15
+ u32_b(1) +
16
+ u32_b(INPUT_USER_SELF)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class HelpConfig
6
+ CONSTRUCTOR = 0xcc1a241e
7
+ CONSTRUCTOR_ALT = 0x3072cfa1
8
+
9
+ attr_reader :flags, :date, :expires, :test_mode, :this_dc, :dc_options
10
+
11
+ def initialize(flags:, date:, expires:, test_mode:, this_dc:, dc_options:)
12
+ @flags = flags
13
+ @date = date
14
+ @expires = expires
15
+ @test_mode = test_mode
16
+ @this_dc = this_dc
17
+ @dc_options = dc_options
18
+ end
19
+
20
+ def self.parse(data)
21
+ constructor = data[0, 4].unpack1('L<')
22
+ raise UnexpectedConstructorError, constructor unless [CONSTRUCTOR, CONSTRUCTOR_ALT].include?(constructor)
23
+
24
+ offset = 4
25
+ flags = data[offset, 4].unpack1('L<')
26
+ offset += 4
27
+ date = data[offset, 4].unpack1('L<')
28
+ offset += 4
29
+ expires = data[offset, 4].unpack1('L<')
30
+ offset += 4
31
+ test_mode = data[offset, 4].unpack1('L<') == 0x997275b5
32
+ offset += 4
33
+ this_dc = data[offset, 4].unpack1('L<')
34
+ offset += 4
35
+
36
+ offset += 4 # vector constructor
37
+ dc_count = data[offset, 4].unpack1('L<')
38
+ offset += 4
39
+
40
+ dc_options = []
41
+ dc_count.times do
42
+ dc_option, offset = parse_dc_option(data, offset)
43
+ dc_options << dc_option
44
+ end
45
+
46
+ new(
47
+ flags: flags, date: date, expires: expires,
48
+ test_mode: test_mode, this_dc: this_dc, dc_options: dc_options
49
+ )
50
+ end
51
+
52
+ class << self
53
+ private
54
+
55
+ def parse_dc_option(data, offset)
56
+ offset += 4 # constructor
57
+ flags = data[offset, 4].unpack1('L<')
58
+ offset += 4
59
+ id = data[offset, 4].unpack1('L<')
60
+ offset += 4
61
+
62
+ ip_len = data.getbyte(offset)
63
+ offset += 1
64
+ ip_address = data[offset, ip_len]
65
+ offset += ip_len
66
+ padding = (4 - ((ip_len + 1) % 4)) % 4
67
+ offset += padding
68
+
69
+ port = data[offset, 4].unpack1('L<')
70
+ offset += 4
71
+
72
+ [{ id: id, ip_address: ip_address, port: port, flags: flags }, offset]
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class ImportLoginToken
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0x95ac5ce4
9
+
10
+ attr_reader :token
11
+
12
+ def initialize(token:)
13
+ @token = token
14
+ end
15
+
16
+ def body
17
+ u32_b(CONSTRUCTOR) + serialize_tl_bytes(@token)
18
+ end
19
+
20
+ private
21
+
22
+ def serialize_tl_bytes(data)
23
+ bytes = data.bytes
24
+ length = bytes.length
25
+
26
+ if length <= 253
27
+ [length] + bytes + padding(length + 1)
28
+ else
29
+ [254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
30
+ end
31
+ end
32
+
33
+ def padding(current_length)
34
+ pad_length = (4 - (current_length % 4)) % 4
35
+ [0] * pad_length
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class InitConnection
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0xc1cd5ea9
9
+
10
+ attr_reader :api_id, :device_model, :system_version, :app_version,
11
+ :system_lang_code, :lang_pack, :lang_code, :query
12
+
13
+ def initialize(api_id:, device_model:, system_version:, app_version:,
14
+ system_lang_code:, lang_pack:, lang_code:, query:)
15
+ @api_id = api_id
16
+ @device_model = device_model
17
+ @system_version = system_version
18
+ @app_version = app_version
19
+ @system_lang_code = system_lang_code
20
+ @lang_pack = lang_pack
21
+ @lang_code = lang_code
22
+ @query = query
23
+ end
24
+
25
+ def body
26
+ flags = 0
27
+
28
+ result = u32_b(CONSTRUCTOR)
29
+ result += u32_b(flags)
30
+ result += u32_b(@api_id)
31
+ result += serialize_tl_string(@device_model)
32
+ result += serialize_tl_string(@system_version)
33
+ result += serialize_tl_string(@app_version)
34
+ result += serialize_tl_string(@system_lang_code)
35
+ result += serialize_tl_string(@lang_pack)
36
+ result += serialize_tl_string(@lang_code)
37
+ result + @query.body
38
+ end
39
+
40
+ private
41
+
42
+ def serialize_tl_string(str)
43
+ bytes = str.encode('UTF-8').bytes
44
+ length = bytes.length
45
+
46
+ if length <= 253
47
+ [length] + bytes + padding(length + 1)
48
+ else
49
+ [254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
50
+ end
51
+ end
52
+
53
+ def padding(current_length)
54
+ pad_length = (4 - (current_length % 4)) % 4
55
+ [0] * pad_length
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class InvokeWithLayer
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0xda9b0d0d
9
+
10
+ attr_reader :layer, :query
11
+
12
+ def initialize(layer:, query:)
13
+ @layer = layer
14
+ @query = query
15
+ end
16
+
17
+ def body
18
+ u32_b(CONSTRUCTOR) + u32_b(@layer) + @query.body
19
+ end
20
+ end
21
+ end
22
+ end