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
|
@@ -56,6 +56,9 @@ module MTProto
|
|
|
56
56
|
AUTH_SIGN_IN = 0x8d52a951
|
|
57
57
|
AUTH_AUTHORIZATION = 0x2ea2c0d4
|
|
58
58
|
AUTH_AUTHORIZATION_SIGN_UP_REQUIRED = 0x44747e9a
|
|
59
|
+
AUTH_EXPORT_AUTHORIZATION = 0xe5bfffcd
|
|
60
|
+
AUTH_EXPORTED_AUTHORIZATION = 0xb434e2b8
|
|
61
|
+
AUTH_IMPORT_AUTHORIZATION = 0xa57a7dad
|
|
59
62
|
AUTH_CHECK_PASSWORD = 0xd18b4d16
|
|
60
63
|
AUTH_EXPORT_LOGIN_TOKEN = 0xb7e085fe
|
|
61
64
|
AUTH_IMPORT_LOGIN_TOKEN = 0x95ac5ce4
|
|
@@ -70,7 +73,7 @@ module MTProto
|
|
|
70
73
|
|
|
71
74
|
# Users
|
|
72
75
|
USERS_GET_USERS = 0x0d91a548
|
|
73
|
-
USER =
|
|
76
|
+
USER = 0x31774388
|
|
74
77
|
|
|
75
78
|
# Contacts
|
|
76
79
|
CONTACTS_GET_CONTACTS = 0x5dd69e12
|
|
@@ -81,25 +84,30 @@ module MTProto
|
|
|
81
84
|
# Messages
|
|
82
85
|
MESSAGES_GET_DIALOGS = 0xa0f4cb4f
|
|
83
86
|
MESSAGES_GET_HISTORY = 0x4423e6c5
|
|
84
|
-
MESSAGES_SEND_MESSAGE =
|
|
85
|
-
MESSAGES_SEND_MEDIA =
|
|
86
|
-
MESSAGES_EDIT_MESSAGE =
|
|
87
|
+
MESSAGES_SEND_MESSAGE = 0xfef48f62
|
|
88
|
+
MESSAGES_SEND_MEDIA = 0x0330e77f
|
|
89
|
+
MESSAGES_EDIT_MESSAGE = 0xb106e66c
|
|
87
90
|
MESSAGES_DELETE_MESSAGES = 0xe58e95d2
|
|
88
91
|
|
|
89
92
|
# Upload + media
|
|
90
93
|
UPLOAD_SAVE_FILE_PART = 0xb304a621
|
|
91
94
|
INPUT_FILE = 0xf52ff27f
|
|
92
|
-
INPUT_MEDIA_UPLOADED_PHOTO =
|
|
95
|
+
INPUT_MEDIA_UPLOADED_PHOTO = 0x7d8375da
|
|
96
|
+
INPUT_MEDIA_UPLOADED_DOCUMENT = 0x037c9330
|
|
97
|
+
DOCUMENT_ATTRIBUTE_FILENAME = 0x15590068
|
|
98
|
+
DOCUMENT_ATTRIBUTE_AUDIO = 0x9852f9c6
|
|
93
99
|
MESSAGES_DIALOGS = 0x15ba6c40
|
|
94
100
|
MESSAGES_DIALOGS_SLICE = 0x71e094f3
|
|
95
|
-
MESSAGE =
|
|
96
|
-
DIALOG =
|
|
101
|
+
MESSAGE = 0x7600b9d3
|
|
102
|
+
DIALOG = 0xfc89f7f3
|
|
97
103
|
CHAT = 0x41cbf256
|
|
98
104
|
CHAT_FORBIDDEN = 0x6592a1a7
|
|
99
|
-
CHANNEL =
|
|
105
|
+
CHANNEL = 0x1c32b11c
|
|
100
106
|
CHANNEL_FORBIDDEN = 0x17d493d5
|
|
101
107
|
|
|
102
108
|
# Updates
|
|
109
|
+
UPDATES = 0x74ae4240
|
|
110
|
+
UPDATES_COMBINED = 0x725b04c3
|
|
103
111
|
UPDATE_NEW_MESSAGE = 0x1f2b0afd
|
|
104
112
|
UPDATE_SHORT = 0x78d4dec1
|
|
105
113
|
UPDATE_SHORT_MESSAGE = 0x313bc7f8
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
# Serializes a BotCommandScope — the `scope:` field shared by
|
|
6
|
+
# bots.setBotCommands / bots.resetBotCommands / bots.getBotCommands.
|
|
7
|
+
#
|
|
8
|
+
# scope is a hash:
|
|
9
|
+
# { type: :default }
|
|
10
|
+
# { type: :users }
|
|
11
|
+
# { type: :chats }
|
|
12
|
+
# { type: :chat_admins }
|
|
13
|
+
# { type: :peer, peer: <input_peer> }
|
|
14
|
+
# { type: :peer_admins, peer: <input_peer> }
|
|
15
|
+
# { type: :peer_user, peer: <input_peer>, user: <input_user> }
|
|
16
|
+
#
|
|
17
|
+
# input_peer is the same shape used elsewhere (e.g. SendMessage):
|
|
18
|
+
# { type: :self | :user | :chat | :channel, id:, access_hash: }
|
|
19
|
+
# input_user:
|
|
20
|
+
# { type: :self } or { id:, access_hash: }
|
|
21
|
+
module BotCommandScope
|
|
22
|
+
extend Binary
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
DEFAULT = 0x2f6cb2ab
|
|
27
|
+
USERS = 0x3c4f04d8
|
|
28
|
+
CHATS = 0x6fe1a881
|
|
29
|
+
CHAT_ADMINS = 0xb9aa606a
|
|
30
|
+
PEER = 0xdb9d897d
|
|
31
|
+
PEER_ADMINS = 0x3fd863d1
|
|
32
|
+
PEER_USER = 0x0a1321f3
|
|
33
|
+
|
|
34
|
+
INPUT_USER = 0xf21158c6
|
|
35
|
+
INPUT_USER_SELF = 0xf7c1b13f
|
|
36
|
+
|
|
37
|
+
def serialize(scope)
|
|
38
|
+
scope ||= { type: :default }
|
|
39
|
+
case scope[:type]
|
|
40
|
+
when :default then u32_b(DEFAULT)
|
|
41
|
+
when :users then u32_b(USERS)
|
|
42
|
+
when :chats then u32_b(CHATS)
|
|
43
|
+
when :chat_admins then u32_b(CHAT_ADMINS)
|
|
44
|
+
when :peer then u32_b(PEER) + serialize_input_peer(scope[:peer])
|
|
45
|
+
when :peer_admins then u32_b(PEER_ADMINS) + serialize_input_peer(scope[:peer])
|
|
46
|
+
when :peer_user
|
|
47
|
+
u32_b(PEER_USER) + serialize_input_peer(scope[:peer]) + serialize_input_user(scope[:user])
|
|
48
|
+
else
|
|
49
|
+
raise ArgumentError, "Unknown bot command scope: #{scope[:type].inspect}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def serialize_input_peer(peer)
|
|
54
|
+
raise ArgumentError, 'scope requires peer:' if peer.nil?
|
|
55
|
+
|
|
56
|
+
case peer[:type]
|
|
57
|
+
when :self
|
|
58
|
+
u32_b(Constructors::INPUT_PEER_SELF)
|
|
59
|
+
when :user
|
|
60
|
+
u32_b(Constructors::INPUT_PEER_USER) + u64_b(peer[:id]) + u64_b(peer[:access_hash] || 0)
|
|
61
|
+
when :chat
|
|
62
|
+
u32_b(Constructors::INPUT_PEER_CHAT) + u64_b(peer[:id])
|
|
63
|
+
when :channel
|
|
64
|
+
u32_b(Constructors::INPUT_PEER_CHANNEL) + u64_b(peer[:id]) + u64_b(peer[:access_hash] || 0)
|
|
65
|
+
else
|
|
66
|
+
raise ArgumentError, "Unknown peer type: #{peer[:type].inspect}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def serialize_input_user(user)
|
|
71
|
+
raise ArgumentError, 'peer_user scope requires user:' if user.nil?
|
|
72
|
+
|
|
73
|
+
if user[:type] == :self
|
|
74
|
+
u32_b(INPUT_USER_SELF)
|
|
75
|
+
else
|
|
76
|
+
u32_b(INPUT_USER) + u64_b(user[:id]) + u64_b(user[:access_hash] || 0)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
# channels.editAdmin — grant, change, or (with no rights) revoke a participant's
|
|
6
|
+
# admin rights in a channel or supergroup. Returns Updates.
|
|
7
|
+
class ChannelsEditAdmin
|
|
8
|
+
include Binary
|
|
9
|
+
|
|
10
|
+
CONSTRUCTOR = 0x9a98ad68
|
|
11
|
+
CHAT_ADMIN_RIGHTS = 0x5fb224d5
|
|
12
|
+
INPUT_USER = 0xf21158c6
|
|
13
|
+
|
|
14
|
+
# Flag bit per chatAdminRights right (the schema leaves bits 6 and 8 unused).
|
|
15
|
+
ADMIN_RIGHT_BITS = {
|
|
16
|
+
change_info: 0, post_messages: 1, edit_messages: 2, delete_messages: 3,
|
|
17
|
+
ban_users: 4, invite_users: 5, pin_messages: 7, add_admins: 9, anonymous: 10,
|
|
18
|
+
manage_call: 11, other: 12, manage_topics: 13, post_stories: 14,
|
|
19
|
+
edit_stories: 15, delete_stories: 16, manage_direct_messages: 17, manage_ranks: 18
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
# channel and user are { id:, access_hash: }. Pass any ADMIN_RIGHT_BITS key as
|
|
23
|
+
# true to grant that right (e.g. post_messages: true); none/all-false revokes
|
|
24
|
+
# the participant's admin status. rank is the optional custom admin title.
|
|
25
|
+
def initialize(channel:, user:, rank: '', **rights)
|
|
26
|
+
unknown = rights.keys - ADMIN_RIGHT_BITS.keys
|
|
27
|
+
raise ArgumentError, "unknown admin right(s): #{unknown.join(', ')}" unless unknown.empty?
|
|
28
|
+
|
|
29
|
+
@channel = channel
|
|
30
|
+
@user = user
|
|
31
|
+
@rank = rank
|
|
32
|
+
@rights = rights
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def serialize
|
|
36
|
+
result = u32_b(CONSTRUCTOR)
|
|
37
|
+
result += u32_b(rank_flag)
|
|
38
|
+
result += serialize_input_channel
|
|
39
|
+
result += serialize_input_user
|
|
40
|
+
result += serialize_admin_rights
|
|
41
|
+
result += serialize_tl_string(@rank) unless @rank.to_s.empty?
|
|
42
|
+
result
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# The method's own flags word: only bit 0, set when the optional rank is present.
|
|
48
|
+
def rank_flag
|
|
49
|
+
@rank.to_s.empty? ? 0 : (1 << 0)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def serialize_input_channel
|
|
53
|
+
u32_b(Constructors::INPUT_CHANNEL) + u64_b(@channel[:id]) + u64_b(@channel[:access_hash])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def serialize_input_user
|
|
57
|
+
u32_b(INPUT_USER) + u64_b(@user[:id]) + u64_b(@user[:access_hash] || 0)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def serialize_admin_rights
|
|
61
|
+
flags = ADMIN_RIGHT_BITS.sum { |right, bit| @rights[right] ? (1 << bit) : 0 }
|
|
62
|
+
u32_b(CHAT_ADMIN_RIGHTS) + u32_b(flags)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def serialize_tl_string(str)
|
|
66
|
+
bytes = str.to_s.b.bytes
|
|
67
|
+
length = bytes.length
|
|
68
|
+
if length <= 253
|
|
69
|
+
[length] + bytes + padding(length + 1)
|
|
70
|
+
else
|
|
71
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def padding(current_length)
|
|
76
|
+
[0] * ((4 - (current_length % 4)) % 4)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
# channels.updateUsername — assign a public username to a channel/supergroup.
|
|
6
|
+
# Returns Bool.
|
|
7
|
+
class ChannelsUpdateUsername
|
|
8
|
+
include Binary
|
|
9
|
+
|
|
10
|
+
CONSTRUCTOR = 0x3514b3de
|
|
11
|
+
|
|
12
|
+
def initialize(channel:, username:)
|
|
13
|
+
@channel = channel
|
|
14
|
+
@username = username
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def serialize
|
|
18
|
+
result = u32_b(CONSTRUCTOR)
|
|
19
|
+
result += u32_b(Constructors::INPUT_CHANNEL) + u64_b(@channel[:id]) + u64_b(@channel[:access_hash])
|
|
20
|
+
result += serialize_tl_string(@username)
|
|
21
|
+
result
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def serialize_tl_string(str)
|
|
27
|
+
bytes = str.encode('UTF-8').bytes
|
|
28
|
+
length = bytes.length
|
|
29
|
+
if length <= 253
|
|
30
|
+
[length] + bytes + padding(length + 1)
|
|
31
|
+
else
|
|
32
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def padding(current_length)
|
|
37
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
38
|
+
[0] * pad_length
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -68,7 +68,7 @@ module MTProto
|
|
|
68
68
|
[contacts, offset]
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
# User parsing mirrors TL::Dialogs.parse_user (user#
|
|
71
|
+
# User parsing mirrors TL::Dialogs.parse_user (user#31774388). Kept private here
|
|
72
72
|
# so this class can be used without instantiating Dialogs.
|
|
73
73
|
def parse_users_vector(data, offset)
|
|
74
74
|
offset += 4 # vector tag
|
|
@@ -6,7 +6,7 @@ module MTProto
|
|
|
6
6
|
module TL
|
|
7
7
|
class Dialogs
|
|
8
8
|
Dialog = Struct.new(:peer_type, :peer_id, :top_message, :unread_count, :pts, keyword_init: true)
|
|
9
|
-
Chat = Struct.new(:id, :title, :type, :access_hash, keyword_init: true)
|
|
9
|
+
Chat = Struct.new(:id, :title, :type, :access_hash, :username, keyword_init: true)
|
|
10
10
|
|
|
11
11
|
SCHEMA_PATH = File.expand_path('../../../../data/tl-schema.json', __dir__)
|
|
12
12
|
|
|
@@ -104,6 +104,7 @@ module MTProto
|
|
|
104
104
|
|
|
105
105
|
offset += 4 # unread_mentions_count
|
|
106
106
|
offset += 4 # unread_reactions_count
|
|
107
|
+
offset += 4 # unread_poll_votes_count (added in layer 227)
|
|
107
108
|
|
|
108
109
|
offset = schema.skip(data, offset) # notify_settings (PeerNotifySettings)
|
|
109
110
|
|
|
@@ -138,12 +139,12 @@ module MTProto
|
|
|
138
139
|
|
|
139
140
|
# --- Messages vector ---
|
|
140
141
|
|
|
141
|
-
# message#
|
|
142
|
+
# message#7600b9d3 flags:# flags2:#
|
|
142
143
|
# id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int
|
|
143
|
-
# peer_id:Peer saved_peer_id:flags.28?Peer
|
|
144
|
+
# from_rank:flags2.12?string peer_id:Peer saved_peer_id:flags.28?Peer
|
|
144
145
|
# fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long
|
|
145
|
-
# via_business_bot_id:flags2.0?long
|
|
146
|
-
# date:int ...
|
|
146
|
+
# via_business_bot_id:flags2.0?long guestchat_via_from:flags2.19?Peer
|
|
147
|
+
# reply_to:flags.3?MessageReplyHeader date:int ...
|
|
147
148
|
#
|
|
148
149
|
# messageService#2b085862 flags:#
|
|
149
150
|
# id:int from_id:flags.8?Peer peer_id:Peer
|
|
@@ -189,11 +190,13 @@ module MTProto
|
|
|
189
190
|
|
|
190
191
|
offset = schema.skip(data, offset) if flags.anybits?(1 << 8) # from_id (Peer)
|
|
191
192
|
offset += 4 if flags.anybits?(1 << 29) # from_boosts_applied
|
|
193
|
+
_, offset = read_tl_string(data, offset) if flags2.anybits?(1 << 12) # from_rank (layer 227)
|
|
192
194
|
offset = schema.skip(data, offset) # peer_id (Peer, always present)
|
|
193
195
|
offset = schema.skip(data, offset) if flags.anybits?(1 << 28) # saved_peer_id
|
|
194
196
|
offset = schema.skip(data, offset) if flags.anybits?(1 << 2) # fwd_from
|
|
195
197
|
offset += 8 if flags.anybits?(1 << 11) # via_bot_id
|
|
196
198
|
offset += 8 if flags2.anybits?(1 << 0) # via_business_bot_id
|
|
199
|
+
offset = schema.skip(data, offset) if flags2.anybits?(1 << 19) # guestchat_via_from (layer 227, Peer)
|
|
197
200
|
offset = schema.skip(data, offset) if flags.anybits?(1 << 3) # reply_to
|
|
198
201
|
|
|
199
202
|
date = data[offset, 4].unpack1('L<')
|
|
@@ -278,7 +281,7 @@ module MTProto
|
|
|
278
281
|
[Chat.new(id: id, title: title, type: :chat), offset]
|
|
279
282
|
end
|
|
280
283
|
|
|
281
|
-
# channel#
|
|
284
|
+
# channel#1c32b11c flags:# flags2:#
|
|
282
285
|
# id:long access_hash:flags.13?long title:string
|
|
283
286
|
# username:flags.6?string photo:ChatPhoto date:int
|
|
284
287
|
# restriction_reason:flags.9?Vector<RestrictionReason>
|
|
@@ -307,7 +310,8 @@ module MTProto
|
|
|
307
310
|
offset += 8
|
|
308
311
|
end
|
|
309
312
|
title, offset = read_tl_string(data, offset)
|
|
310
|
-
|
|
313
|
+
username = nil
|
|
314
|
+
username, offset = read_tl_string(data, offset) if flags.anybits?(1 << 6) # username
|
|
311
315
|
offset = schema.skip(data, offset) # photo (ChatPhoto)
|
|
312
316
|
offset += 4 # date
|
|
313
317
|
if flags.anybits?(1 << 9) # restriction_reason Vector<RestrictionReason>
|
|
@@ -320,7 +324,7 @@ module MTProto
|
|
|
320
324
|
if flags2.anybits?(1 << 0) # usernames Vector<Username>
|
|
321
325
|
offset = schema.skip_vector(data, offset) { |d, o| schema.skip(d, o) }
|
|
322
326
|
end
|
|
323
|
-
offset
|
|
327
|
+
offset = schema.skip(data, offset) if flags2.anybits?(1 << 4) # stories_max_id (layer 227: RecentStory)
|
|
324
328
|
offset = schema.skip(data, offset) if flags2.anybits?(1 << 7) # color (PeerColor)
|
|
325
329
|
offset = schema.skip(data, offset) if flags2.anybits?(1 << 8) # profile_color (PeerColor)
|
|
326
330
|
offset = schema.skip(data, offset) if flags2.anybits?(1 << 9) # emoji_status
|
|
@@ -331,7 +335,7 @@ module MTProto
|
|
|
331
335
|
offset += 8 if flags2.anybits?(1 << 18) # linked_monoforum_id (long)
|
|
332
336
|
|
|
333
337
|
type = flags.anybits?(1 << 8) ? :supergroup : :channel
|
|
334
|
-
[Chat.new(id: id, title: title, type: type, access_hash: access_hash), offset]
|
|
338
|
+
[Chat.new(id: id, title: title, type: type, access_hash: access_hash, username: username), offset]
|
|
335
339
|
end
|
|
336
340
|
|
|
337
341
|
# chatForbidden#6592a1a7 id:long title:string
|
|
@@ -373,7 +377,7 @@ module MTProto
|
|
|
373
377
|
|
|
374
378
|
USER_EMPTY = 0xd3bc4b7a
|
|
375
379
|
|
|
376
|
-
# user#
|
|
380
|
+
# user#31774388 flags:# flags2:#
|
|
377
381
|
# id:long access_hash:flags.0?long
|
|
378
382
|
# first_name:flags.1?string last_name:flags.2?string
|
|
379
383
|
# username:flags.3?string phone:flags.4?string
|
|
@@ -418,7 +422,9 @@ module MTProto
|
|
|
418
422
|
last_name = nil
|
|
419
423
|
last_name, offset = read_tl_string(data, offset) if flags.anybits?(1 << 2)
|
|
420
424
|
|
|
421
|
-
|
|
425
|
+
username = nil
|
|
426
|
+
username, offset = read_tl_string(data, offset) if flags.anybits?(1 << 3) # username
|
|
427
|
+
|
|
422
428
|
offset = skip_tl_string(data, offset) if flags.anybits?(1 << 4) # phone
|
|
423
429
|
offset = schema.skip(data, offset) if flags.anybits?(1 << 5) # photo
|
|
424
430
|
offset = schema.skip(data, offset) if flags.anybits?(1 << 6) # status
|
|
@@ -430,14 +436,14 @@ module MTProto
|
|
|
430
436
|
offset = skip_tl_string(data, offset) if flags.anybits?(1 << 22) # lang_code
|
|
431
437
|
offset = schema.skip(data, offset) if flags.anybits?(1 << 30) # emoji_status
|
|
432
438
|
offset = schema.skip_vector(data, offset) { |d, o| schema.skip(d, o) } if flags2.anybits?(1 << 0) # usernames
|
|
433
|
-
offset
|
|
439
|
+
offset = schema.skip(data, offset) if flags2.anybits?(1 << 5) # stories_max_id (layer 227: RecentStory)
|
|
434
440
|
offset = schema.skip(data, offset) if flags2.anybits?(1 << 8) # color
|
|
435
441
|
offset = schema.skip(data, offset) if flags2.anybits?(1 << 9) # profile_color
|
|
436
442
|
offset += 4 if flags2.anybits?(1 << 12) # bot_active_users
|
|
437
443
|
offset += 8 if flags2.anybits?(1 << 14) # bot_verification_icon
|
|
438
444
|
offset += 8 if flags2.anybits?(1 << 15) # send_paid_messages_stars
|
|
439
445
|
|
|
440
|
-
[{ id: id, first_name: first_name, last_name: last_name, access_hash: access_hash }, offset]
|
|
446
|
+
[{ id: id, first_name: first_name, last_name: last_name, username: username, access_hash: access_hash }, offset]
|
|
441
447
|
end
|
|
442
448
|
|
|
443
449
|
# --- TL string ---
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class ExportAuthorization
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
def initialize(dc_id:)
|
|
9
|
+
@dc_id = dc_id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def serialize
|
|
13
|
+
u32_b(Constructors::AUTH_EXPORT_AUTHORIZATION) + u32_b(@dc_id)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class ExportedAuthorization
|
|
6
|
+
attr_reader :id, :bytes
|
|
7
|
+
|
|
8
|
+
def initialize(id:, bytes:)
|
|
9
|
+
@id = id
|
|
10
|
+
@bytes = bytes
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.deserialize(data)
|
|
14
|
+
constructor = data[0, 4].unpack1('L<')
|
|
15
|
+
raise UnexpectedConstructorError, constructor unless constructor == Constructors::AUTH_EXPORTED_AUTHORIZATION
|
|
16
|
+
|
|
17
|
+
id = data[4, 8].unpack1('Q<')
|
|
18
|
+
new(id: id, bytes: read_tl_bytes(data, 12))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.read_tl_bytes(data, offset)
|
|
22
|
+
first = data.getbyte(offset)
|
|
23
|
+
if first == 254
|
|
24
|
+
len = data.getbyte(offset + 1) | (data.getbyte(offset + 2) << 8) | (data.getbyte(offset + 3) << 16)
|
|
25
|
+
data[offset + 4, len]
|
|
26
|
+
else
|
|
27
|
+
data[offset + 1, first]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -7,19 +7,22 @@ module MTProto
|
|
|
7
7
|
class ForwardMessages
|
|
8
8
|
include Binary
|
|
9
9
|
|
|
10
|
-
CONSTRUCTOR =
|
|
10
|
+
CONSTRUCTOR = 0x13704a7c
|
|
11
11
|
|
|
12
|
-
def initialize(from_peer:, to_peer:, ids:, random_ids: nil, drop_author: false, drop_media_captions: false
|
|
12
|
+
def initialize(from_peer:, to_peer:, ids:, random_ids: nil, drop_author: false, drop_media_captions: false,
|
|
13
|
+
silent: false)
|
|
13
14
|
@from_peer = from_peer
|
|
14
15
|
@to_peer = to_peer
|
|
15
16
|
@ids = ids
|
|
16
17
|
@random_ids = random_ids || Array.new(ids.length) { SecureRandom.random_number(2**63) }
|
|
17
18
|
@drop_author = drop_author
|
|
18
19
|
@drop_media_captions = drop_media_captions
|
|
20
|
+
@silent = silent
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def serialize
|
|
22
24
|
flags = 0
|
|
25
|
+
flags |= (1 << 5) if @silent
|
|
23
26
|
flags |= (1 << 11) if @drop_author
|
|
24
27
|
flags |= (1 << 12) if @drop_media_captions
|
|
25
28
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
# messages.getBotCallbackAnswer — the press itself: the user client invokes
|
|
6
|
+
# this with the button's callback data; the server delivers an
|
|
7
|
+
# updateBotCallbackQuery to the bot and blocks until the bot answers (or
|
|
8
|
+
# times out), then returns messages.botCallbackAnswer.
|
|
9
|
+
class GetBotCallbackAnswer
|
|
10
|
+
include Binary
|
|
11
|
+
|
|
12
|
+
CONSTRUCTOR = 0x9342ca07
|
|
13
|
+
|
|
14
|
+
def initialize(peer:, msg_id:, data: nil, game: false)
|
|
15
|
+
@peer = peer
|
|
16
|
+
@msg_id = msg_id
|
|
17
|
+
@data = data
|
|
18
|
+
@game = game
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def serialize
|
|
22
|
+
flags = 0
|
|
23
|
+
flags |= (1 << 0) if @data
|
|
24
|
+
flags |= (1 << 1) if @game
|
|
25
|
+
|
|
26
|
+
result = u32_b(CONSTRUCTOR)
|
|
27
|
+
result += u32_b(flags)
|
|
28
|
+
result += serialize_input_peer
|
|
29
|
+
result += u32_b(@msg_id)
|
|
30
|
+
result += serialize_tl_bytes(@data) if @data
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def serialize_input_peer
|
|
37
|
+
case @peer[:type]
|
|
38
|
+
when :self
|
|
39
|
+
u32_b(Constructors::INPUT_PEER_SELF)
|
|
40
|
+
when :user
|
|
41
|
+
u32_b(Constructors::INPUT_PEER_USER) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
42
|
+
when :chat
|
|
43
|
+
u32_b(Constructors::INPUT_PEER_CHAT) + u64_b(@peer[:id])
|
|
44
|
+
when :channel
|
|
45
|
+
u32_b(Constructors::INPUT_PEER_CHANNEL) + u64_b(@peer[:id]) + u64_b(@peer[:access_hash] || 0)
|
|
46
|
+
else
|
|
47
|
+
raise "Unknown peer type: #{@peer[:type]}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def serialize_tl_bytes(bytes_str)
|
|
52
|
+
bytes = bytes_str.to_s.b.bytes
|
|
53
|
+
length = bytes.length
|
|
54
|
+
if length <= 253
|
|
55
|
+
[length] + bytes + padding(length + 1)
|
|
56
|
+
else
|
|
57
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def padding(current_length)
|
|
62
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
63
|
+
[0] * pad_length
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'bot_command_scope'
|
|
4
|
+
|
|
5
|
+
module MTProto
|
|
6
|
+
module TL
|
|
7
|
+
# bots.getBotCommands — fetch the bot's commands for a given scope/language.
|
|
8
|
+
# Returns Vector<BotCommand>. Result parsing belongs to a later layer; this
|
|
9
|
+
# object only builds the request.
|
|
10
|
+
class GetBotCommands
|
|
11
|
+
include Binary
|
|
12
|
+
|
|
13
|
+
CONSTRUCTOR = 0xe34c0dd6
|
|
14
|
+
|
|
15
|
+
# scope: BotCommandScope hash (see BotCommandScope); defaults to default scope.
|
|
16
|
+
def initialize(scope: { type: :default }, lang_code: '')
|
|
17
|
+
@scope = scope
|
|
18
|
+
@lang_code = lang_code
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def serialize
|
|
22
|
+
result = u32_b(CONSTRUCTOR)
|
|
23
|
+
result += BotCommandScope.serialize(@scope)
|
|
24
|
+
result += serialize_tl_string(@lang_code)
|
|
25
|
+
result
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def serialize_tl_string(str)
|
|
31
|
+
bytes = str.to_s.encode('UTF-8').bytes
|
|
32
|
+
length = bytes.length
|
|
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
|
|
@@ -7,10 +7,18 @@ module MTProto
|
|
|
7
7
|
|
|
8
8
|
CONSTRUCTOR = 0xbe5335be
|
|
9
9
|
INPUT_PHOTO_FILE_LOCATION = 0x40181ffe
|
|
10
|
+
INPUT_DOCUMENT_FILE_LOCATION = 0xbad07584
|
|
11
|
+
|
|
12
|
+
LOCATION_CONSTRUCTORS = {
|
|
13
|
+
photo: INPUT_PHOTO_FILE_LOCATION,
|
|
14
|
+
document: INPUT_DOCUMENT_FILE_LOCATION
|
|
15
|
+
}.freeze
|
|
10
16
|
|
|
11
17
|
# location: { id:, access_hash:, file_reference: (binary String), thumb_size: (String) }
|
|
12
|
-
|
|
18
|
+
# type: :photo for photos, :document for documents/voice/video/audio.
|
|
19
|
+
def initialize(location:, type: :photo, offset: 0, limit: 1024 * 1024)
|
|
13
20
|
@location = location
|
|
21
|
+
@type = type
|
|
14
22
|
@offset = offset
|
|
15
23
|
@limit = limit
|
|
16
24
|
end
|
|
@@ -27,7 +35,7 @@ module MTProto
|
|
|
27
35
|
private
|
|
28
36
|
|
|
29
37
|
def serialize_location
|
|
30
|
-
u32_b(
|
|
38
|
+
u32_b(LOCATION_CONSTRUCTORS.fetch(@type)) +
|
|
31
39
|
u64_b(@location[:id]) +
|
|
32
40
|
u64_b(@location[:access_hash]) +
|
|
33
41
|
serialize_tl_bytes(@location[:file_reference]) +
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MTProto
|
|
4
|
+
module TL
|
|
5
|
+
class ImportAuthorization
|
|
6
|
+
include Binary
|
|
7
|
+
|
|
8
|
+
def initialize(id:, bytes:)
|
|
9
|
+
@id = id
|
|
10
|
+
@bytes = bytes
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def serialize
|
|
14
|
+
u32_b(Constructors::AUTH_IMPORT_AUTHORIZATION) +
|
|
15
|
+
u64_b(@id) +
|
|
16
|
+
serialize_tl_bytes(@bytes)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def serialize_tl_bytes(value)
|
|
22
|
+
bytes = value.to_s.b.bytes
|
|
23
|
+
length = bytes.length
|
|
24
|
+
|
|
25
|
+
if length <= 253
|
|
26
|
+
[length] + bytes + padding(length + 1)
|
|
27
|
+
else
|
|
28
|
+
[254] + u32_b(length)[0, 3] + bytes + padding(length + 4)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def padding(current_length)
|
|
33
|
+
pad_length = (4 - (current_length % 4)) % 4
|
|
34
|
+
[0] * pad_length
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|