mtproto 0.0.8 → 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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/ext/aes_ige/extconf.rb +3 -9
  3. data/ext/factorization/extconf.rb +2 -0
  4. data/lib/mtproto/auth_key_generator.rb +68 -105
  5. data/lib/mtproto/binary.rb +21 -0
  6. data/lib/mtproto/client/api/check_password.rb +41 -0
  7. data/lib/mtproto/client/api/export_login_token.rb +27 -0
  8. data/lib/mtproto/client/api/get_updates_difference.rb +21 -0
  9. data/lib/mtproto/client/api/get_updates_state.rb +14 -0
  10. data/lib/mtproto/client/api/get_users.rb +14 -0
  11. data/lib/mtproto/client/api/import_login_token.rb +23 -0
  12. data/lib/mtproto/client/api/send_code.rb +21 -0
  13. data/lib/mtproto/client/api/sign_in.rb +27 -0
  14. data/lib/mtproto/client/api.rb +28 -0
  15. data/lib/mtproto/client/rpc/response.rb +63 -0
  16. data/lib/mtproto/client/rpc.rb +61 -125
  17. data/lib/mtproto/client.rb +142 -31
  18. data/lib/mtproto/crypto/dh_key_exchange.rb +1 -2
  19. data/lib/mtproto/crypto/dh_validator.rb +17 -19
  20. data/lib/mtproto/crypto/factorization.rb +1 -1
  21. data/lib/mtproto/crypto/rsa_key.rb +2 -2
  22. data/lib/mtproto/crypto/srp.rb +117 -0
  23. data/lib/mtproto/delegate_methods.rb +11 -0
  24. data/lib/mtproto/message/message.rb +85 -0
  25. data/lib/mtproto/session.rb +1 -1
  26. data/lib/mtproto/tl/constructors.rb +2269 -0
  27. data/lib/mtproto/tl/object.rb +25 -0
  28. data/lib/mtproto/tl/objects/account_password.rb +72 -0
  29. data/lib/mtproto/tl/objects/authorization.rb +73 -0
  30. data/lib/mtproto/tl/objects/check_password.rb +46 -0
  31. data/lib/mtproto/tl/objects/client_dh_inner_data.rb +47 -0
  32. data/lib/mtproto/tl/objects/dh_gen_response.rb +50 -0
  33. data/lib/mtproto/tl/objects/export_login_token.rb +51 -0
  34. data/lib/mtproto/tl/objects/get_config.rb +15 -0
  35. data/lib/mtproto/tl/objects/get_difference.rb +36 -0
  36. data/lib/mtproto/tl/objects/get_password.rb +15 -0
  37. data/lib/mtproto/tl/objects/get_state.rb +15 -0
  38. data/lib/mtproto/tl/objects/get_users.rb +20 -0
  39. data/lib/mtproto/tl/objects/help_config.rb +77 -0
  40. data/lib/mtproto/tl/objects/import_login_token.rb +39 -0
  41. data/lib/mtproto/tl/objects/init_connection.rb +59 -0
  42. data/lib/mtproto/tl/objects/invoke_with_layer.rb +22 -0
  43. data/lib/mtproto/tl/objects/login_token.rb +82 -0
  44. data/lib/mtproto/tl/objects/pq_inner_data.rb +69 -0
  45. data/lib/mtproto/tl/objects/req_dh_params.rb +65 -0
  46. data/lib/mtproto/tl/objects/req_pq_multi.rb +23 -0
  47. data/lib/mtproto/tl/objects/res_pq.rb +75 -0
  48. data/lib/mtproto/tl/objects/send_code.rb +50 -0
  49. data/lib/mtproto/tl/objects/sent_code.rb +79 -0
  50. data/lib/mtproto/tl/objects/server_dh_inner_data.rb +74 -0
  51. data/lib/mtproto/tl/objects/server_dh_params.rb +53 -0
  52. data/lib/mtproto/tl/objects/set_client_dh_params.rb +48 -0
  53. data/lib/mtproto/tl/objects/sign_in.rb +47 -0
  54. data/lib/mtproto/tl/objects/update.rb +80 -0
  55. data/lib/mtproto/tl/objects/update_short.rb +22 -0
  56. data/lib/mtproto/tl/objects/update_short_message.rb +67 -0
  57. data/lib/mtproto/tl/objects/updates_difference.rb +157 -0
  58. data/lib/mtproto/tl/objects/updates_state.rb +37 -0
  59. data/lib/mtproto/tl/objects/users.rb +86 -0
  60. data/lib/mtproto/transport/abridged_packet_codec.rb +35 -12
  61. data/lib/mtproto/transport/connection.rb +23 -0
  62. data/lib/mtproto/transport/errors.rb +11 -0
  63. data/lib/mtproto/transport/packet.rb +19 -0
  64. data/lib/mtproto/transport/tcp_connection.rb +57 -46
  65. data/lib/mtproto/type/bad_msg_notification.rb +10 -10
  66. data/lib/mtproto/type/gzip_packed.rb +5 -3
  67. data/lib/mtproto/type/message.rb +2 -2
  68. data/lib/mtproto/type/rpc_error.rb +0 -1
  69. data/lib/mtproto/updates_poller.rb +37 -33
  70. data/lib/mtproto/version.rb +1 -1
  71. data/lib/mtproto.rb +11 -17
  72. data/scripts/generate_constructors.rb +65 -0
  73. metadata +62 -51
  74. data/lib/mtproto/async/middleware/base.rb +0 -17
  75. data/lib/mtproto/async/middleware/flood_wait.rb +0 -42
  76. data/lib/mtproto/async/request.rb +0 -18
  77. data/lib/mtproto/async/request_queue.rb +0 -63
  78. data/lib/mtproto/async_client.rb +0 -201
  79. data/lib/mtproto/rpc/get_config.rb +0 -34
  80. data/lib/mtproto/rpc/get_contacts.rb +0 -29
  81. data/lib/mtproto/rpc/get_updates_difference.rb +0 -51
  82. data/lib/mtproto/rpc/get_updates_state.rb +0 -29
  83. data/lib/mtproto/rpc/get_users.rb +0 -29
  84. data/lib/mtproto/rpc/ping.rb +0 -33
  85. data/lib/mtproto/rpc/send_code.rb +0 -41
  86. data/lib/mtproto/rpc/send_message.rb +0 -47
  87. data/lib/mtproto/rpc/sign_in.rb +0 -48
  88. data/lib/mtproto/type/auth_key/dh_gen_response.rb +0 -37
  89. data/lib/mtproto/type/auth_key/req_dh_params.rb +0 -31
  90. data/lib/mtproto/type/auth_key/req_pq_multi.rb +0 -18
  91. data/lib/mtproto/type/auth_key/res_pq.rb +0 -62
  92. data/lib/mtproto/type/auth_key/server_dh_params.rb +0 -43
  93. data/lib/mtproto/type/auth_key/set_client_dh_params.rb +0 -25
  94. data/lib/mtproto/type/code_settings.rb +0 -25
  95. data/lib/mtproto/type/config.rb +0 -124
  96. data/lib/mtproto/type/rpc/auth/authorization.rb +0 -107
  97. data/lib/mtproto/type/rpc/auth/send_code.rb +0 -28
  98. data/lib/mtproto/type/rpc/auth/sent_code.rb +0 -36
  99. data/lib/mtproto/type/rpc/auth/sign_in.rb +0 -32
  100. data/lib/mtproto/type/rpc/contacts/contacts.rb +0 -155
  101. data/lib/mtproto/type/rpc/contacts/get_contacts.rb +0 -18
  102. data/lib/mtproto/type/rpc/help/config.rb +0 -35
  103. data/lib/mtproto/type/rpc/help/get_config.rb +0 -17
  104. data/lib/mtproto/type/rpc/init_connection.rb +0 -28
  105. data/lib/mtproto/type/rpc/invoke_with_layer.rb +0 -19
  106. data/lib/mtproto/type/rpc/messages/send_message.rb +0 -43
  107. data/lib/mtproto/type/rpc/messages/updates.rb +0 -87
  108. data/lib/mtproto/type/rpc/ping.rb +0 -18
  109. data/lib/mtproto/type/rpc/pong.rb +0 -46
  110. data/lib/mtproto/type/rpc/updates/difference.rb +0 -332
  111. data/lib/mtproto/type/rpc/updates/get_difference.rb +0 -42
  112. data/lib/mtproto/type/rpc/updates/get_state.rb +0 -17
  113. data/lib/mtproto/type/rpc/updates/state.rb +0 -59
  114. data/lib/mtproto/type/rpc/users/get_users.rb +0 -25
  115. data/lib/mtproto/type/rpc/users/users.rb +0 -99
  116. data/lib/mtproto/type/sent_code.rb +0 -128
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'authorization'
4
+
5
+ module MTProto
6
+ module TL
7
+ class LoginToken
8
+ CONSTRUCTOR_TOKEN = 0x629f1980
9
+ CONSTRUCTOR_MIGRATE_TO = 0x068e9916
10
+ CONSTRUCTOR_SUCCESS = 0x390d5c5e
11
+
12
+ attr_reader :type, :expires, :token, :dc_id, :authorization
13
+
14
+ def initialize(type:, expires: nil, token: nil, dc_id: nil, authorization: nil)
15
+ @type = type
16
+ @expires = expires
17
+ @token = token
18
+ @dc_id = dc_id
19
+ @authorization = authorization
20
+ end
21
+
22
+ def user_id
23
+ @authorization&.user_id
24
+ end
25
+
26
+ def access_hash
27
+ @authorization&.access_hash
28
+ end
29
+
30
+ def success?
31
+ @type == :success
32
+ end
33
+
34
+ def self.parse(data)
35
+ constructor = data[0, 4].unpack1('L<')
36
+
37
+ case constructor
38
+ when CONSTRUCTOR_TOKEN
39
+ parse_token(data)
40
+ when CONSTRUCTOR_MIGRATE_TO
41
+ parse_migrate_to(data)
42
+ when CONSTRUCTOR_SUCCESS
43
+ new(type: :success, authorization: Authorization.parse(data[4..]))
44
+ else
45
+ raise UnexpectedConstructorError, constructor
46
+ end
47
+ end
48
+
49
+ class << self
50
+ private
51
+
52
+ def parse_token(data)
53
+ offset = 4
54
+ expires = data[offset, 4].unpack1('L<')
55
+ offset += 4
56
+ token = read_tl_bytes(data, offset)
57
+ new(type: :token, expires: expires, token: token)
58
+ end
59
+
60
+ def parse_migrate_to(data)
61
+ offset = 4
62
+ dc_id = data[offset, 4].unpack1('L<')
63
+ offset += 4
64
+ token = read_tl_bytes(data, offset)
65
+ new(type: :migrate_to, dc_id: dc_id, token: token)
66
+ end
67
+
68
+ def read_tl_bytes(data, offset)
69
+ first_byte = data.getbyte(offset)
70
+ if first_byte < 254
71
+ data[offset + 1, first_byte]
72
+ else
73
+ len = data.getbyte(offset + 1) |
74
+ (data.getbyte(offset + 2) << 8) |
75
+ (data.getbyte(offset + 3) << 16)
76
+ data[offset + 4, len]
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class PQInnerData
6
+ include Binary
7
+
8
+ CONSTRUCTOR_DC = 0xa9f55f95
9
+ CONSTRUCTOR_TEMP_DC = 0x56fddf88
10
+
11
+ attr_reader :pq, :p, :q, :nonce, :server_nonce, :new_nonce, :dc, :expires_in
12
+
13
+ def initialize(pq:, p:, q:, nonce:, server_nonce:, new_nonce:, dc:, expires_in: nil)
14
+ @pq = pq
15
+ @p = p
16
+ @q = q
17
+ @nonce = nonce
18
+ @server_nonce = server_nonce
19
+ @new_nonce = new_nonce
20
+ @dc = dc
21
+ @expires_in = expires_in
22
+ end
23
+
24
+ def body
25
+ constructor = @expires_in ? CONSTRUCTOR_TEMP_DC : CONSTRUCTOR_DC
26
+
27
+ result = u32_b(constructor)
28
+ result += serialize_tl_bytes(integer_to_bytes(@pq))
29
+ result += serialize_tl_bytes(integer_to_bytes(@p))
30
+ result += serialize_tl_bytes(integer_to_bytes(@q))
31
+ result += @nonce.bytes
32
+ result += @server_nonce.bytes
33
+ result += @new_nonce.bytes
34
+ result += u32_b(@expires_in) if @expires_in
35
+ result += u32_b(@dc)
36
+
37
+ result
38
+ end
39
+
40
+ private
41
+
42
+ def serialize_tl_bytes(bytes)
43
+ length = bytes.length
44
+
45
+ if length <= 253
46
+ [length] + bytes + padding(length + 1)
47
+ else
48
+ [254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
49
+ end
50
+ end
51
+
52
+ def padding(current_length)
53
+ pad_length = (4 - (current_length % 4)) % 4
54
+ [0] * pad_length
55
+ end
56
+
57
+ def integer_to_bytes(int)
58
+ return [0] if int.zero?
59
+
60
+ bytes = []
61
+ while int > 0
62
+ bytes.unshift(int & 0xff)
63
+ int >>= 8
64
+ end
65
+ bytes
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class ReqDHParams
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0xd712e4be
9
+
10
+ attr_reader :nonce, :server_nonce, :p, :q, :public_key_fingerprint, :encrypted_data
11
+
12
+ def initialize(nonce:, server_nonce:, p:, q:, public_key_fingerprint:, encrypted_data:)
13
+ raise ArgumentError, 'Nonce must be 16 bytes' unless nonce.bytesize == 16
14
+ raise ArgumentError, 'Server nonce must be 16 bytes' unless server_nonce.bytesize == 16
15
+
16
+ @nonce = nonce
17
+ @server_nonce = server_nonce
18
+ @p = p
19
+ @q = q
20
+ @public_key_fingerprint = public_key_fingerprint
21
+ @encrypted_data = encrypted_data
22
+ end
23
+
24
+ def body
25
+ result = u32_b(CONSTRUCTOR)
26
+ result += @nonce.bytes
27
+ result += @server_nonce.bytes
28
+ result += serialize_tl_bytes(integer_to_bytes(@p))
29
+ result += serialize_tl_bytes(integer_to_bytes(@q))
30
+ result += u64_b(@public_key_fingerprint)
31
+ result += serialize_tl_bytes(@encrypted_data.bytes)
32
+
33
+ result
34
+ end
35
+
36
+ private
37
+
38
+ def serialize_tl_bytes(bytes)
39
+ length = bytes.length
40
+
41
+ if length <= 253
42
+ [length] + bytes + padding(length + 1)
43
+ else
44
+ [254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
45
+ end
46
+ end
47
+
48
+ def padding(current_length)
49
+ pad_length = (4 - (current_length % 4)) % 4
50
+ [0] * pad_length
51
+ end
52
+
53
+ def integer_to_bytes(int)
54
+ return [0] if int.zero?
55
+
56
+ bytes = []
57
+ while int > 0
58
+ bytes.unshift(int & 0xff)
59
+ int >>= 8
60
+ end
61
+ bytes
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class ReqPqMulti
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0xbe7e8ef1
9
+
10
+ attr_reader :nonce
11
+
12
+ def initialize(nonce)
13
+ raise ArgumentError, 'Nonce must be 16 bytes' unless nonce.bytesize == 16
14
+
15
+ @nonce = nonce
16
+ end
17
+
18
+ def body
19
+ u32_b(CONSTRUCTOR) + @nonce.bytes
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class ResPq
6
+ extend Binary
7
+
8
+ CONSTRUCTOR = 0x05162463
9
+
10
+ attr_reader :nonce, :server_nonce, :pq, :fingerprints
11
+
12
+ def self.parse(message)
13
+ data = message.body
14
+ constructor = b_u32(data[0, 4])
15
+ raise "Unexpected constructor: 0x#{constructor.to_s(16)}" unless constructor == CONSTRUCTOR
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
+ pq_length_byte = data[offset]
26
+ offset += 1
27
+
28
+ pq_length = if pq_length_byte == 254
29
+ b_u32(data[offset, 3] + [0]) & 0xffffff
30
+ offset += 3
31
+ else
32
+ pq_length_byte
33
+ end
34
+
35
+ pq = data[offset, pq_length].pack('C*')
36
+ offset += pq_length
37
+ offset += padding_length(pq_length + 1)
38
+
39
+ vector_constructor = b_u32(data[offset, 4])
40
+ offset += 4
41
+ raise 'Expected vector constructor' unless vector_constructor == 0x1cb5c415
42
+
43
+ fingerprints_count = b_u32(data[offset, 4])
44
+ offset += 4
45
+
46
+ fingerprints = []
47
+ fingerprints_count.times do
48
+ fingerprints << b_u64(data[offset, 8])
49
+ offset += 8
50
+ end
51
+
52
+ new(
53
+ nonce: nonce,
54
+ server_nonce: server_nonce,
55
+ pq: pq,
56
+ fingerprints: fingerprints
57
+ )
58
+ end
59
+
60
+ def self.padding_length(length)
61
+ (4 - (length % 4)) % 4
62
+ end
63
+ private_class_method :padding_length
64
+
65
+ private
66
+
67
+ def initialize(nonce:, server_nonce:, pq:, fingerprints:)
68
+ @nonce = nonce
69
+ @server_nonce = server_nonce
70
+ @pq = pq
71
+ @fingerprints = fingerprints
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class SendCode
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0xa677244f
9
+ CODE_SETTINGS = 0xad253d78
10
+
11
+ attr_reader :phone_number, :api_id, :api_hash
12
+
13
+ def initialize(phone_number:, api_id:, api_hash:)
14
+ @phone_number = phone_number
15
+ @api_id = api_id
16
+ @api_hash = api_hash
17
+ end
18
+
19
+ def body
20
+ u32_b(CONSTRUCTOR) +
21
+ serialize_tl_string(@phone_number) +
22
+ u32_b(@api_id) +
23
+ serialize_tl_string(@api_hash) +
24
+ code_settings
25
+ end
26
+
27
+ private
28
+
29
+ def code_settings
30
+ u32_b(CODE_SETTINGS) + u32_b(0)
31
+ end
32
+
33
+ def serialize_tl_string(str)
34
+ bytes = str.encode('UTF-8').bytes
35
+ length = bytes.length
36
+
37
+ if length <= 253
38
+ [length] + bytes + padding(length + 1)
39
+ else
40
+ [254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
41
+ end
42
+ end
43
+
44
+ def padding(current_length)
45
+ pad_length = (4 - (current_length % 4)) % 4
46
+ [0] * pad_length
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class SentCode
6
+ CONSTRUCTOR = 0x5e002502
7
+
8
+ attr_reader :flags, :type, :phone_code_hash, :next_type, :timeout
9
+
10
+ def initialize(flags:, type:, phone_code_hash:, next_type: nil, timeout: nil)
11
+ @flags = flags
12
+ @type = type
13
+ @phone_code_hash = phone_code_hash
14
+ @next_type = next_type
15
+ @timeout = timeout
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
+ type, offset = parse_sent_code_type(data, offset)
27
+
28
+ phone_code_hash, offset = read_tl_string(data, offset)
29
+
30
+ next_type = nil
31
+ next_type, offset = parse_code_type(data, offset) if flags.anybits?(1 << 1)
32
+
33
+ timeout = nil
34
+ timeout = data[offset, 4].unpack1('L<') if flags.anybits?(1 << 2)
35
+
36
+ new(flags: flags, type: type, phone_code_hash: phone_code_hash, next_type: next_type, timeout: timeout)
37
+ end
38
+
39
+ class << self
40
+ private
41
+
42
+ def parse_sent_code_type(data, offset)
43
+ constructor = data[offset, 4].unpack1('L<')
44
+ offset += 4
45
+
46
+ case constructor
47
+ when 0x3dbb5986, 0xc000bba2, 0x5353e5a7 # app, sms, 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
+ CONSTRUCTOR = 0xb5890dba
7
+
8
+ attr_reader :nonce, :server_nonce, :g, :dh_prime, :g_a, :server_time
9
+
10
+ def self.parse(bytes)
11
+ constructor = bytes[0, 4].unpack1('L<')
12
+ raise "Unexpected constructor: 0x#{constructor.to_s(16)}" unless constructor == CONSTRUCTOR
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
+ CONSTRUCTOR = 0xd0e8075c
9
+
10
+ attr_reader :nonce, :server_nonce, :encrypted_answer
11
+
12
+ def self.parse(message)
13
+ data = message.body
14
+ constructor = b_u32(data[0, 4])
15
+ raise "Unexpected constructor: 0x#{constructor.to_s(16)}" unless constructor == CONSTRUCTOR
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,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class SetClientDHParams
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0xf5045f1f
9
+
10
+ attr_reader :nonce, :server_nonce, :encrypted_data
11
+
12
+ def initialize(nonce:, server_nonce:, encrypted_data:)
13
+ raise ArgumentError, 'Nonce must be 16 bytes' unless nonce.bytesize == 16
14
+ raise ArgumentError, 'Server nonce must be 16 bytes' unless server_nonce.bytesize == 16
15
+
16
+ @nonce = nonce
17
+ @server_nonce = server_nonce
18
+ @encrypted_data = encrypted_data
19
+ end
20
+
21
+ def body
22
+ result = u32_b(CONSTRUCTOR)
23
+ result += @nonce.bytes
24
+ result += @server_nonce.bytes
25
+ result += serialize_tl_bytes(@encrypted_data.bytes)
26
+
27
+ result
28
+ end
29
+
30
+ private
31
+
32
+ def serialize_tl_bytes(bytes)
33
+ length = bytes.length
34
+
35
+ if length <= 253
36
+ [length] + bytes + padding(length + 1)
37
+ else
38
+ [254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
39
+ end
40
+ end
41
+
42
+ def padding(current_length)
43
+ pad_length = (4 - (current_length % 4)) % 4
44
+ [0] * pad_length
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTProto
4
+ module TL
5
+ class SignIn
6
+ include Binary
7
+
8
+ CONSTRUCTOR = 0x8d52a951
9
+
10
+ attr_reader :phone_number, :phone_code_hash, :phone_code
11
+
12
+ def initialize(phone_number:, phone_code_hash:, phone_code:)
13
+ @phone_number = phone_number
14
+ @phone_code_hash = phone_code_hash
15
+ @phone_code = phone_code
16
+ end
17
+
18
+ def body
19
+ flags = 1 << 0
20
+
21
+ u32_b(CONSTRUCTOR) +
22
+ u32_b(flags) +
23
+ serialize_tl_string(@phone_number) +
24
+ serialize_tl_string(@phone_code_hash) +
25
+ serialize_tl_string(@phone_code)
26
+ end
27
+
28
+ private
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