mtproto 0.0.15 → 0.0.19
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 +47158 -42684
- data/lib/mtproto/auth_key_generator.rb +2 -2
- data/lib/mtproto/client/api/export_authorization.rb +17 -0
- data/lib/mtproto/client/api/import_authorization.rb +23 -0
- data/lib/mtproto/client/api.rb +2 -0
- data/lib/mtproto/client.rb +1 -1
- data/lib/mtproto/file_downloader.rb +122 -0
- data/lib/mtproto/tl/constructor_names.rb +314 -109
- data/lib/mtproto/tl/constructors.rb +16 -8
- data/lib/mtproto/tl/objects/bot_command_scope.rb +81 -0
- data/lib/mtproto/tl/objects/channels_edit_admin.rb +80 -0
- data/lib/mtproto/tl/objects/channels_join_channel.rb +1 -1
- data/lib/mtproto/tl/objects/channels_update_username.rb +42 -0
- data/lib/mtproto/tl/objects/contacts.rb +1 -1
- data/lib/mtproto/tl/objects/dialogs.rb +19 -13
- data/lib/mtproto/tl/objects/export_authorization.rb +17 -0
- data/lib/mtproto/tl/objects/exported_authorization.rb +32 -0
- data/lib/mtproto/tl/objects/forward_messages.rb +5 -2
- data/lib/mtproto/tl/objects/get_bot_callback_answer.rb +67 -0
- data/lib/mtproto/tl/objects/get_bot_commands.rb +46 -0
- data/lib/mtproto/tl/objects/get_file.rb +10 -2
- data/lib/mtproto/tl/objects/import_authorization.rb +38 -0
- data/lib/mtproto/tl/objects/keyboard_button_callback.rb +50 -0
- data/lib/mtproto/tl/objects/message.rb +97 -21
- data/lib/mtproto/tl/objects/messages.rb +7 -74
- data/lib/mtproto/tl/objects/reply_inline_markup.rb +30 -0
- data/lib/mtproto/tl/objects/reset_bot_commands.rb +45 -0
- data/lib/mtproto/tl/objects/send_media.rb +76 -4
- data/lib/mtproto/tl/objects/send_message.rb +4 -2
- data/lib/mtproto/tl/objects/send_message_action.rb +48 -0
- data/lib/mtproto/tl/objects/set_bot_callback_answer.rb +54 -0
- data/lib/mtproto/tl/objects/set_bot_commands.rb +6 -3
- data/lib/mtproto/tl/objects/set_bot_guest_chat_result.rb +84 -0
- data/lib/mtproto/tl/objects/set_typing.rb +49 -0
- data/lib/mtproto/tl/objects/update_status.rb +24 -0
- data/lib/mtproto/tl/objects/updates.rb +117 -0
- data/lib/mtproto/tl/objects/updates_difference.rb +16 -119
- data/lib/mtproto/tl/reader.rb +188 -0
- data/lib/mtproto/transport/abridged_packet_codec.rb +5 -1
- data/lib/mtproto/unencrypted_message.rb +39 -0
- data/lib/mtproto/version.rb +1 -1
- data/lib/mtproto.rb +4 -1
- data/scripts/gen_constructor_names.rb +72 -0
- data/scripts/tl_to_json.rb +72 -0
- data/scripts/verify_ids.rb +33 -0
- metadata +26 -2
- data/lib/mtproto/message/message.rb +0 -85
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
# The unencrypted MTProto transport envelope (auth_key_id=0 | msg_id | len | body),
|
|
5
|
+
# used for the plaintext request/response of the DH key exchange. Its encrypted
|
|
6
|
+
# sibling is EncryptedMessage; the runtime never decrypts through this class.
|
|
7
|
+
class UnencryptedMessage
|
|
8
|
+
include Binary
|
|
9
|
+
extend Binary
|
|
10
|
+
|
|
11
|
+
attr_reader :auth_key_id, :msg_id, :body
|
|
12
|
+
|
|
13
|
+
def initialize(body, msg_id: self.class.generate_msg_id, auth_key_id: 0)
|
|
14
|
+
@auth_key_id = auth_key_id
|
|
15
|
+
@msg_id = msg_id
|
|
16
|
+
@body = body
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.parse(packet)
|
|
20
|
+
data = packet.data
|
|
21
|
+
msg_id = b_u64(data[8, 8])
|
|
22
|
+
body_length = b_u32(data[16, 4])
|
|
23
|
+
body = data[20, body_length]
|
|
24
|
+
|
|
25
|
+
new(body, msg_id: msg_id, auth_key_id: 0)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def bytes
|
|
29
|
+
u64_b(@auth_key_id) +
|
|
30
|
+
u64_b(@msg_id) +
|
|
31
|
+
u32_b(@body.length) +
|
|
32
|
+
@body
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.generate_msg_id
|
|
36
|
+
(Time.now.to_f * (2**32)).to_i & ~3
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/mtproto/version.rb
CHANGED
data/lib/mtproto.rb
CHANGED
|
@@ -9,13 +9,15 @@ require_relative 'mtproto/transport/packet'
|
|
|
9
9
|
require_relative 'mtproto/transport/abridged_packet_codec'
|
|
10
10
|
require_relative 'mtproto/transport/tcp_connection'
|
|
11
11
|
require_relative 'mtproto/transport/connection'
|
|
12
|
-
require_relative 'mtproto/
|
|
12
|
+
require_relative 'mtproto/unencrypted_message'
|
|
13
13
|
require_relative 'mtproto/tl/constructors'
|
|
14
14
|
require_relative 'mtproto/tl/constructor_names'
|
|
15
|
+
require_relative 'mtproto/tl/reader'
|
|
15
16
|
require_relative 'mtproto/tl/object'
|
|
16
17
|
require_relative 'mtproto/tl/objects/update'
|
|
17
18
|
require_relative 'mtproto/tl/objects/update_short'
|
|
18
19
|
require_relative 'mtproto/tl/objects/update_short_message'
|
|
20
|
+
require_relative 'mtproto/tl/objects/updates'
|
|
19
21
|
require_relative 'mtproto/tl/objects/message'
|
|
20
22
|
require_relative 'mtproto/tl/objects/msg_container'
|
|
21
23
|
require_relative 'mtproto/tl/objects/new_session_created'
|
|
@@ -33,6 +35,7 @@ require_relative 'mtproto/auth_key_generator'
|
|
|
33
35
|
require_relative 'mtproto/session'
|
|
34
36
|
require_relative 'mtproto/encrypted_message'
|
|
35
37
|
require_relative 'mtproto/client'
|
|
38
|
+
require_relative 'mtproto/file_downloader'
|
|
36
39
|
|
|
37
40
|
module MTProto
|
|
38
41
|
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Regenerate lib/mtproto/tl/constructor_names.rb (the id -> name map used only for
|
|
5
|
+
# logging and error text) from the LOCAL data/tl-schema.json (current layer),
|
|
6
|
+
# preserving the stable MTProto transport-layer names the API schema lacks.
|
|
7
|
+
#
|
|
8
|
+
# Why not scripts/generate_constructors.rb: that one fetches
|
|
9
|
+
# core.telegram.org/schema/json, which is STALE (~layer 214, no guest mode), and
|
|
10
|
+
# overwrites constructors.rb. This one is offline and uses the migrated schema.
|
|
11
|
+
#
|
|
12
|
+
# Run: ruby scripts/gen_constructor_names.rb
|
|
13
|
+
|
|
14
|
+
require 'json'
|
|
15
|
+
|
|
16
|
+
root = File.expand_path('..', __dir__)
|
|
17
|
+
schema = JSON.parse(File.read(File.join(root, 'data/tl-schema.json')))
|
|
18
|
+
names_file = File.join(root, 'lib/mtproto/tl/constructor_names.rb')
|
|
19
|
+
|
|
20
|
+
api = {} # unsigned id => predicate/method name
|
|
21
|
+
api_names = {} # name => true
|
|
22
|
+
schema.fetch('constructors').each do |c|
|
|
23
|
+
api[c['id'].to_i & 0xffffffff] = c['predicate']
|
|
24
|
+
api_names[c['predicate']] = true
|
|
25
|
+
end
|
|
26
|
+
schema.fetch('methods').each do |m|
|
|
27
|
+
api[m['id'].to_i & 0xffffffff] = m['method']
|
|
28
|
+
api_names[m['method']] = true
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Preserve MTProto transport-layer names (rpc_result, msgs_ack, dh_gen_*, ...) that
|
|
32
|
+
# the API schema does not carry. An existing id absent from the API schema is
|
|
33
|
+
# transport-core UNLESS its name is an API predicate/method — that marks a pre-bump
|
|
34
|
+
# constructor whose id changed, so drop it (the current id is already in `api`).
|
|
35
|
+
core = {}
|
|
36
|
+
File.foreach(names_file) do |line|
|
|
37
|
+
next unless line =~ /0x([0-9a-fA-F]{8})\s*=>\s*'([^']+)'/
|
|
38
|
+
|
|
39
|
+
id = Regexp.last_match(1).to_i(16)
|
|
40
|
+
name = Regexp.last_match(2)
|
|
41
|
+
next if api.key?(id) || api_names.key?(name)
|
|
42
|
+
|
|
43
|
+
core[id] = name
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
entries = api.merge(core).sort.map { |id, name| format(" 0x%08x => '%s'", id, name) }
|
|
47
|
+
|
|
48
|
+
out = []
|
|
49
|
+
out << '# frozen_string_literal: true'
|
|
50
|
+
out << ''
|
|
51
|
+
out << '# rubocop:disable Metrics/ModuleLength'
|
|
52
|
+
out << ''
|
|
53
|
+
out << '# Auto-generated id -> constructor/method name map (logging + error messages).'
|
|
54
|
+
out << '# API names from data/tl-schema.json (current layer); MTProto transport-layer'
|
|
55
|
+
out << '# names preserved from the prior map.'
|
|
56
|
+
out << '# Run: ruby scripts/gen_constructor_names.rb'
|
|
57
|
+
out << ''
|
|
58
|
+
out << "require_relative 'constructors'"
|
|
59
|
+
out << ''
|
|
60
|
+
out << 'module MTProto'
|
|
61
|
+
out << ' module TL'
|
|
62
|
+
out << ' module ConstructorNames'
|
|
63
|
+
out << ' NAMES = {'
|
|
64
|
+
entries.each_with_index { |e, i| out << (i == entries.size - 1 ? e : "#{e},") }
|
|
65
|
+
out << ' }.freeze'
|
|
66
|
+
out << ' end'
|
|
67
|
+
out << ' end'
|
|
68
|
+
out << 'end'
|
|
69
|
+
out << '# rubocop:enable Metrics/ModuleLength'
|
|
70
|
+
|
|
71
|
+
File.write(names_file, "#{out.join("\n")}\n")
|
|
72
|
+
puts "wrote #{api.size + core.size} entries (#{api.size} api + #{core.size} transport-core)"
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
#
|
|
4
|
+
# Convert a tdesktop-style TL schema (.tl) into mtproto-ruby's tl-schema.json
|
|
5
|
+
# format ({ "constructors": [...], "methods": [...] }, each entry
|
|
6
|
+
# { id (signed int32 string), predicate|method, params:[{name,type}], type }).
|
|
7
|
+
#
|
|
8
|
+
# Telegram's published core.telegram.org/schema JSON lags the live layer (it is
|
|
9
|
+
# still ~214 with no guest constructors), so the authoritative current source is
|
|
10
|
+
# tdesktop's Telegram/SourceFiles/mtproto/scheme/api.tl (layer 225).
|
|
11
|
+
#
|
|
12
|
+
# Usage: ruby tl_to_json.rb api.tl [mtproto.tl ...] > tl-schema.json
|
|
13
|
+
|
|
14
|
+
require 'json'
|
|
15
|
+
|
|
16
|
+
def signed32(hexid)
|
|
17
|
+
u = hexid.to_i(16)
|
|
18
|
+
u >= (1 << 31) ? u - (1 << 32) : u
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Params come straight from the .tl tokens: "name:type" where type is already in
|
|
22
|
+
# the gem's native form ("#", "flags.8?Peer", "Vector<Message>", "long", "!X").
|
|
23
|
+
# Skip generic declarations ("{X:Type}") and bare core noise ("#", "[", "t", "]").
|
|
24
|
+
def parse_params(tokens)
|
|
25
|
+
tokens.each_with_object([]) do |tok, acc|
|
|
26
|
+
next if tok.start_with?('{')
|
|
27
|
+
next unless tok.include?(':')
|
|
28
|
+
|
|
29
|
+
name, type = tok.split(':', 2)
|
|
30
|
+
acc << { 'name' => name, 'type' => type }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
constructors = []
|
|
35
|
+
methods = []
|
|
36
|
+
section = :constructors
|
|
37
|
+
|
|
38
|
+
ARGV.each do |path|
|
|
39
|
+
File.foreach(path) do |raw|
|
|
40
|
+
line = raw.strip
|
|
41
|
+
next if line.empty? || line.start_with?('//')
|
|
42
|
+
|
|
43
|
+
if line == '---functions---'
|
|
44
|
+
section = :methods
|
|
45
|
+
next
|
|
46
|
+
end
|
|
47
|
+
if line == '---types---'
|
|
48
|
+
section = :constructors
|
|
49
|
+
next
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
next unless line.include?('=') && line.end_with?(';')
|
|
53
|
+
|
|
54
|
+
body = line[0..-2] # drop trailing ';'
|
|
55
|
+
lhs, rhs = body.split('=', 2)
|
|
56
|
+
lhs_tokens = lhs.split(/\s+/)
|
|
57
|
+
head = lhs_tokens.shift
|
|
58
|
+
next unless head&.include?('#') # skip id-less core types ("int ? = Int;")
|
|
59
|
+
|
|
60
|
+
name, hexid = head.split('#', 2)
|
|
61
|
+
entry = {
|
|
62
|
+
'id' => signed32(hexid).to_s,
|
|
63
|
+
(section == :constructors ? 'predicate' : 'method') => name,
|
|
64
|
+
'params' => parse_params(lhs_tokens),
|
|
65
|
+
'type' => rhs.strip
|
|
66
|
+
}
|
|
67
|
+
(section == :constructors ? constructors : methods) << entry
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
warn "constructors=#{constructors.size} methods=#{methods.size}"
|
|
72
|
+
puts JSON.pretty_generate('constructors' => constructors, 'methods' => methods)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Flag every hardcoded 0x id in the gem's lib that is NOT a valid layer-227
|
|
3
|
+
# constructor/method id (api.tl). Survivors are either mtproto-layer ids (fine,
|
|
4
|
+
# they live in mtproto.tl) or genuinely-changed api ids (must be updated).
|
|
5
|
+
require 'set'
|
|
6
|
+
|
|
7
|
+
tl = ARGV[0]
|
|
8
|
+
libdir = ARGV[1]
|
|
9
|
+
|
|
10
|
+
ids = Set.new
|
|
11
|
+
names = {}
|
|
12
|
+
File.foreach(tl) do |l|
|
|
13
|
+
next unless l =~ /\A([\w.]+)#([0-9a-f]+)/
|
|
14
|
+
ids << Regexp.last_match(2).to_i(16)
|
|
15
|
+
names[Regexp.last_match(2).to_i(16)] = Regexp.last_match(1)
|
|
16
|
+
end
|
|
17
|
+
warn "api227 ids: #{ids.size}"
|
|
18
|
+
|
|
19
|
+
IGNORE = %w[0xffffffff 0x7fffffff 0x80000000 0x00000000 0xfffffffe].freeze
|
|
20
|
+
seen = {}
|
|
21
|
+
Dir.glob("#{libdir}/**/*.rb").each do |f|
|
|
22
|
+
File.foreach(f).with_index do |line, i|
|
|
23
|
+
line.scan(/0x[0-9a-fA-F]{6,8}/).each do |tok|
|
|
24
|
+
t = tok.downcase
|
|
25
|
+
next if IGNORE.include?(t)
|
|
26
|
+
next if ids.include?(t.to_i(16))
|
|
27
|
+
(seen[t] ||= []) << "#{File.basename(f)}:#{i + 1}"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
puts "=== gem 0x ids NOT present as a layer-227 api constructor/method ==="
|
|
33
|
+
seen.sort.each { |tok, locs| puts format('%-12s %s', tok, locs.uniq.join(', ')) }
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mtproto
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.19
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Artem Levenkov
|
|
@@ -63,6 +63,7 @@ files:
|
|
|
63
63
|
- lib/mtproto/client.rb
|
|
64
64
|
- lib/mtproto/client/api.rb
|
|
65
65
|
- lib/mtproto/client/api/check_password.rb
|
|
66
|
+
- lib/mtproto/client/api/export_authorization.rb
|
|
66
67
|
- lib/mtproto/client/api/export_login_token.rb
|
|
67
68
|
- lib/mtproto/client/api/get_contacts.rb
|
|
68
69
|
- lib/mtproto/client/api/get_dialogs.rb
|
|
@@ -70,6 +71,7 @@ files:
|
|
|
70
71
|
- lib/mtproto/client/api/get_updates_difference.rb
|
|
71
72
|
- lib/mtproto/client/api/get_updates_state.rb
|
|
72
73
|
- lib/mtproto/client/api/get_users.rb
|
|
74
|
+
- lib/mtproto/client/api/import_authorization.rb
|
|
73
75
|
- lib/mtproto/client/api/import_login_token.rb
|
|
74
76
|
- lib/mtproto/client/api/send_code.rb
|
|
75
77
|
- lib/mtproto/client/api/send_message.rb
|
|
@@ -88,7 +90,7 @@ files:
|
|
|
88
90
|
- lib/mtproto/delegate_methods.rb
|
|
89
91
|
- lib/mtproto/encrypted_message.rb
|
|
90
92
|
- lib/mtproto/errors.rb
|
|
91
|
-
- lib/mtproto/
|
|
93
|
+
- lib/mtproto/file_downloader.rb
|
|
92
94
|
- lib/mtproto/message_id.rb
|
|
93
95
|
- lib/mtproto/session.rb
|
|
94
96
|
- lib/mtproto/tl/constructor_names.rb
|
|
@@ -96,15 +98,18 @@ files:
|
|
|
96
98
|
- lib/mtproto/tl/object.rb
|
|
97
99
|
- lib/mtproto/tl/objects/account_password.rb
|
|
98
100
|
- lib/mtproto/tl/objects/authorization.rb
|
|
101
|
+
- lib/mtproto/tl/objects/bot_command_scope.rb
|
|
99
102
|
- lib/mtproto/tl/objects/channels_create_channel.rb
|
|
100
103
|
- lib/mtproto/tl/objects/channels_delete_messages.rb
|
|
101
104
|
- lib/mtproto/tl/objects/channels_delete_participant_history.rb
|
|
105
|
+
- lib/mtproto/tl/objects/channels_edit_admin.rb
|
|
102
106
|
- lib/mtproto/tl/objects/channels_edit_banned.rb
|
|
103
107
|
- lib/mtproto/tl/objects/channels_get_messages.rb
|
|
104
108
|
- lib/mtproto/tl/objects/channels_get_participant.rb
|
|
105
109
|
- lib/mtproto/tl/objects/channels_join_channel.rb
|
|
106
110
|
- lib/mtproto/tl/objects/channels_leave_channel.rb
|
|
107
111
|
- lib/mtproto/tl/objects/channels_report_spam.rb
|
|
112
|
+
- lib/mtproto/tl/objects/channels_update_username.rb
|
|
108
113
|
- lib/mtproto/tl/objects/check_password.rb
|
|
109
114
|
- lib/mtproto/tl/objects/client_dh_inner_data.rb
|
|
110
115
|
- lib/mtproto/tl/objects/contacts.rb
|
|
@@ -114,11 +119,15 @@ files:
|
|
|
114
119
|
- lib/mtproto/tl/objects/dialogs.rb
|
|
115
120
|
- lib/mtproto/tl/objects/edit_access_settings.rb
|
|
116
121
|
- lib/mtproto/tl/objects/edit_message.rb
|
|
122
|
+
- lib/mtproto/tl/objects/export_authorization.rb
|
|
117
123
|
- lib/mtproto/tl/objects/export_bot_token.rb
|
|
118
124
|
- lib/mtproto/tl/objects/export_login_token.rb
|
|
125
|
+
- lib/mtproto/tl/objects/exported_authorization.rb
|
|
119
126
|
- lib/mtproto/tl/objects/exported_bot_token.rb
|
|
120
127
|
- lib/mtproto/tl/objects/forward_messages.rb
|
|
121
128
|
- lib/mtproto/tl/objects/get_access_settings.rb
|
|
129
|
+
- lib/mtproto/tl/objects/get_bot_callback_answer.rb
|
|
130
|
+
- lib/mtproto/tl/objects/get_bot_commands.rb
|
|
122
131
|
- lib/mtproto/tl/objects/get_channel_difference.rb
|
|
123
132
|
- lib/mtproto/tl/objects/get_config.rb
|
|
124
133
|
- lib/mtproto/tl/objects/get_contacts.rb
|
|
@@ -134,12 +143,14 @@ files:
|
|
|
134
143
|
- lib/mtproto/tl/objects/get_users.rb
|
|
135
144
|
- lib/mtproto/tl/objects/gzip_packed.rb
|
|
136
145
|
- lib/mtproto/tl/objects/help_config.rb
|
|
146
|
+
- lib/mtproto/tl/objects/import_authorization.rb
|
|
137
147
|
- lib/mtproto/tl/objects/import_bot_authorization.rb
|
|
138
148
|
- lib/mtproto/tl/objects/import_login_token.rb
|
|
139
149
|
- lib/mtproto/tl/objects/init_connection.rb
|
|
140
150
|
- lib/mtproto/tl/objects/input_keyboard_button_request_peer.rb
|
|
141
151
|
- lib/mtproto/tl/objects/invite_to_channel.rb
|
|
142
152
|
- lib/mtproto/tl/objects/invoke_with_layer.rb
|
|
153
|
+
- lib/mtproto/tl/objects/keyboard_button_callback.rb
|
|
143
154
|
- lib/mtproto/tl/objects/login_token.rb
|
|
144
155
|
- lib/mtproto/tl/objects/message.rb
|
|
145
156
|
- lib/mtproto/tl/objects/messages.rb
|
|
@@ -148,11 +159,13 @@ files:
|
|
|
148
159
|
- lib/mtproto/tl/objects/new_session_created.rb
|
|
149
160
|
- lib/mtproto/tl/objects/pq_inner_data.rb
|
|
150
161
|
- lib/mtproto/tl/objects/raw_response.rb
|
|
162
|
+
- lib/mtproto/tl/objects/reply_inline_markup.rb
|
|
151
163
|
- lib/mtproto/tl/objects/reply_keyboard_markup.rb
|
|
152
164
|
- lib/mtproto/tl/objects/req_dh_params.rb
|
|
153
165
|
- lib/mtproto/tl/objects/req_pq_multi.rb
|
|
154
166
|
- lib/mtproto/tl/objects/request_peer_type_create_bot.rb
|
|
155
167
|
- lib/mtproto/tl/objects/res_pq.rb
|
|
168
|
+
- lib/mtproto/tl/objects/reset_bot_commands.rb
|
|
156
169
|
- lib/mtproto/tl/objects/resolve_username.rb
|
|
157
170
|
- lib/mtproto/tl/objects/rpc_error.rb
|
|
158
171
|
- lib/mtproto/tl/objects/save_file_part.rb
|
|
@@ -160,31 +173,42 @@ files:
|
|
|
160
173
|
- lib/mtproto/tl/objects/send_code.rb
|
|
161
174
|
- lib/mtproto/tl/objects/send_media.rb
|
|
162
175
|
- lib/mtproto/tl/objects/send_message.rb
|
|
176
|
+
- lib/mtproto/tl/objects/send_message_action.rb
|
|
163
177
|
- lib/mtproto/tl/objects/send_reaction.rb
|
|
164
178
|
- lib/mtproto/tl/objects/sent_code.rb
|
|
165
179
|
- lib/mtproto/tl/objects/server_dh_inner_data.rb
|
|
166
180
|
- lib/mtproto/tl/objects/server_dh_params.rb
|
|
181
|
+
- lib/mtproto/tl/objects/set_bot_callback_answer.rb
|
|
167
182
|
- lib/mtproto/tl/objects/set_bot_commands.rb
|
|
183
|
+
- lib/mtproto/tl/objects/set_bot_guest_chat_result.rb
|
|
168
184
|
- lib/mtproto/tl/objects/set_bot_info.rb
|
|
169
185
|
- lib/mtproto/tl/objects/set_client_dh_params.rb
|
|
186
|
+
- lib/mtproto/tl/objects/set_typing.rb
|
|
170
187
|
- lib/mtproto/tl/objects/sign_in.rb
|
|
171
188
|
- lib/mtproto/tl/objects/update.rb
|
|
172
189
|
- lib/mtproto/tl/objects/update_short.rb
|
|
173
190
|
- lib/mtproto/tl/objects/update_short_message.rb
|
|
174
191
|
- lib/mtproto/tl/objects/update_short_sent_message.rb
|
|
192
|
+
- lib/mtproto/tl/objects/update_status.rb
|
|
175
193
|
- lib/mtproto/tl/objects/update_username.rb
|
|
194
|
+
- lib/mtproto/tl/objects/updates.rb
|
|
176
195
|
- lib/mtproto/tl/objects/updates_difference.rb
|
|
177
196
|
- lib/mtproto/tl/objects/updates_state.rb
|
|
178
197
|
- lib/mtproto/tl/objects/upload_profile_photo.rb
|
|
179
198
|
- lib/mtproto/tl/objects/users.rb
|
|
199
|
+
- lib/mtproto/tl/reader.rb
|
|
180
200
|
- lib/mtproto/tl/schema.rb
|
|
181
201
|
- lib/mtproto/transport/abridged_packet_codec.rb
|
|
182
202
|
- lib/mtproto/transport/connection.rb
|
|
183
203
|
- lib/mtproto/transport/errors.rb
|
|
184
204
|
- lib/mtproto/transport/packet.rb
|
|
185
205
|
- lib/mtproto/transport/tcp_connection.rb
|
|
206
|
+
- lib/mtproto/unencrypted_message.rb
|
|
186
207
|
- lib/mtproto/version.rb
|
|
208
|
+
- scripts/gen_constructor_names.rb
|
|
187
209
|
- scripts/generate_constructors.rb
|
|
210
|
+
- scripts/tl_to_json.rb
|
|
211
|
+
- scripts/verify_ids.rb
|
|
188
212
|
- tmp/.keep
|
|
189
213
|
homepage: https://github.com/alev-pro/mtproto-ruby
|
|
190
214
|
licenses:
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module MTProto
|
|
4
|
-
class Message
|
|
5
|
-
include Binary
|
|
6
|
-
extend Binary
|
|
7
|
-
|
|
8
|
-
attr_reader :auth_key_id, :msg_id, :body,
|
|
9
|
-
:msg_key, :encrypted_data,
|
|
10
|
-
:server_salt, :session_id, :seq_no
|
|
11
|
-
|
|
12
|
-
def initialize(body, msg_id: self.class.generate_msg_id, auth_key_id: 0)
|
|
13
|
-
@auth_key_id = auth_key_id
|
|
14
|
-
@msg_id = msg_id
|
|
15
|
-
@body = body
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def self.parse(packet)
|
|
19
|
-
data = packet.data
|
|
20
|
-
auth_key_id = b_u64(data[0, 8])
|
|
21
|
-
|
|
22
|
-
if auth_key_id.zero?
|
|
23
|
-
parse_unencrypted(data)
|
|
24
|
-
else
|
|
25
|
-
parse_encrypted(data, auth_key_id)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def encrypted?
|
|
30
|
-
!@auth_key_id.zero?
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def decrypt(auth_key:, sender: :server)
|
|
34
|
-
raise 'Message is not encrypted' unless encrypted?
|
|
35
|
-
|
|
36
|
-
keys = Crypto::MessageKey.derive_aes_key_iv(auth_key, @msg_key, sender: sender)
|
|
37
|
-
plaintext = Crypto::AES_IGE.decrypt_ige(@encrypted_data, keys[:aes_key], keys[:aes_iv])
|
|
38
|
-
|
|
39
|
-
expected_msg_key = Crypto::MessageKey.generate_msg_key(auth_key, plaintext, sender: sender)
|
|
40
|
-
raise 'msg_key mismatch!' unless @msg_key == expected_msg_key
|
|
41
|
-
|
|
42
|
-
offset = 0
|
|
43
|
-
@server_salt = plaintext[offset, 8].unpack1('Q<')
|
|
44
|
-
offset += 8
|
|
45
|
-
@session_id = plaintext[offset, 8].unpack1('Q<')
|
|
46
|
-
offset += 8
|
|
47
|
-
@msg_id = plaintext[offset, 8].unpack1('Q<')
|
|
48
|
-
offset += 8
|
|
49
|
-
@seq_no = plaintext[offset, 4].unpack1('L<')
|
|
50
|
-
offset += 4
|
|
51
|
-
body_length = plaintext[offset, 4].unpack1('L<')
|
|
52
|
-
offset += 4
|
|
53
|
-
@body = plaintext[offset, body_length].bytes
|
|
54
|
-
|
|
55
|
-
self
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def bytes
|
|
59
|
-
u64_b(@auth_key_id) +
|
|
60
|
-
u64_b(@msg_id) +
|
|
61
|
-
u32_b(@body.length) +
|
|
62
|
-
@body
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def self.generate_msg_id
|
|
66
|
-
(Time.now.to_f * (2**32)).to_i & ~3
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
private_class_method def self.parse_unencrypted(data)
|
|
70
|
-
msg_id = b_u64(data[8, 8])
|
|
71
|
-
body_length = b_u32(data[16, 4])
|
|
72
|
-
body = data[20, body_length]
|
|
73
|
-
|
|
74
|
-
new(body, msg_id: msg_id, auth_key_id: 0)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
private_class_method def self.parse_encrypted(data, auth_key_id)
|
|
78
|
-
msg = allocate
|
|
79
|
-
msg.instance_variable_set(:@auth_key_id, auth_key_id)
|
|
80
|
-
msg.instance_variable_set(:@msg_key, data[8, 16].pack('C*'))
|
|
81
|
-
msg.instance_variable_set(:@encrypted_data, data[24..].pack('C*'))
|
|
82
|
-
msg
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|