mtproto 0.0.6 → 0.0.8

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +4 -0
  3. data/lib/mtproto/async/middleware/base.rb +17 -0
  4. data/lib/mtproto/async/middleware/flood_wait.rb +42 -0
  5. data/lib/mtproto/async/request.rb +18 -0
  6. data/lib/mtproto/async/request_queue.rb +63 -0
  7. data/lib/mtproto/async_client.rb +201 -0
  8. data/lib/mtproto/auth_key_generator.rb +22 -12
  9. data/lib/mtproto/client/rpc.rb +165 -0
  10. data/lib/mtproto/client.rb +65 -176
  11. data/lib/mtproto/crypto/aes_ige.rb +1 -1
  12. data/lib/mtproto/crypto/factorization.rb +1 -1
  13. data/lib/mtproto/message_id.rb +13 -0
  14. data/lib/mtproto/rpc/get_config.rb +34 -0
  15. data/lib/mtproto/rpc/get_contacts.rb +29 -0
  16. data/lib/mtproto/rpc/get_updates_difference.rb +51 -0
  17. data/lib/mtproto/rpc/get_updates_state.rb +29 -0
  18. data/lib/mtproto/rpc/get_users.rb +29 -0
  19. data/lib/mtproto/rpc/ping.rb +33 -0
  20. data/lib/mtproto/rpc/send_code.rb +41 -0
  21. data/lib/mtproto/rpc/send_message.rb +47 -0
  22. data/lib/mtproto/rpc/sign_in.rb +48 -0
  23. data/lib/mtproto/type/auth_key/dh_gen_response.rb +37 -0
  24. data/lib/mtproto/type/auth_key/req_dh_params.rb +31 -0
  25. data/lib/mtproto/type/auth_key/req_pq_multi.rb +18 -0
  26. data/lib/mtproto/type/auth_key/res_pq.rb +62 -0
  27. data/lib/mtproto/type/auth_key/server_dh_params.rb +43 -0
  28. data/lib/mtproto/type/auth_key/set_client_dh_params.rb +25 -0
  29. data/lib/mtproto/{tl → type}/bad_msg_notification.rb +1 -1
  30. data/lib/mtproto/{tl → type}/client_dh_inner_data.rb +1 -1
  31. data/lib/mtproto/{tl → type}/code_settings.rb +1 -1
  32. data/lib/mtproto/{tl → type}/config.rb +1 -1
  33. data/lib/mtproto/{tl → type}/gzip_packed.rb +1 -1
  34. data/lib/mtproto/type/message.rb +38 -0
  35. data/lib/mtproto/{tl → type}/msg_container.rb +1 -1
  36. data/lib/mtproto/{tl → type}/new_session_created.rb +1 -1
  37. data/lib/mtproto/{tl/p_q_inner_data.rb → type/pq_inner_data.rb} +1 -1
  38. data/lib/mtproto/type/rpc/auth/authorization.rb +107 -0
  39. data/lib/mtproto/type/rpc/auth/send_code.rb +28 -0
  40. data/lib/mtproto/type/rpc/auth/sent_code.rb +36 -0
  41. data/lib/mtproto/type/rpc/auth/sign_in.rb +32 -0
  42. data/lib/mtproto/type/rpc/contacts/contacts.rb +155 -0
  43. data/lib/mtproto/type/rpc/contacts/get_contacts.rb +18 -0
  44. data/lib/mtproto/type/rpc/help/config.rb +35 -0
  45. data/lib/mtproto/type/rpc/help/get_config.rb +17 -0
  46. data/lib/mtproto/type/rpc/init_connection.rb +28 -0
  47. data/lib/mtproto/type/rpc/invoke_with_layer.rb +19 -0
  48. data/lib/mtproto/type/rpc/messages/send_message.rb +43 -0
  49. data/lib/mtproto/type/rpc/messages/updates.rb +87 -0
  50. data/lib/mtproto/type/rpc/ping.rb +18 -0
  51. data/lib/mtproto/type/rpc/pong.rb +46 -0
  52. data/lib/mtproto/type/rpc/updates/difference.rb +332 -0
  53. data/lib/mtproto/type/rpc/updates/get_difference.rb +42 -0
  54. data/lib/mtproto/type/rpc/updates/get_state.rb +17 -0
  55. data/lib/mtproto/type/rpc/updates/state.rb +59 -0
  56. data/lib/mtproto/type/rpc/users/get_users.rb +25 -0
  57. data/lib/mtproto/type/rpc/users/users.rb +99 -0
  58. data/lib/mtproto/{tl → type}/rpc_error.rb +1 -1
  59. data/lib/mtproto/{tl → type}/sent_code.rb +1 -1
  60. data/lib/mtproto/{tl → type}/serializer.rb +1 -1
  61. data/lib/mtproto/{tl → type}/server_dh_inner_data.rb +1 -1
  62. data/lib/mtproto/updates_poller.rb +111 -0
  63. data/lib/mtproto/version.rb +1 -1
  64. data/lib/mtproto.rb +28 -14
  65. metadata +86 -18
  66. data/ext/aes_ige/Makefile +0 -273
  67. data/ext/factorization/Makefile +0 -273
  68. data/lib/mtproto/connection.rb +0 -103
  69. data/lib/mtproto/tl/message.rb +0 -252
@@ -1,273 +0,0 @@
1
-
2
- SHELL = /bin/sh
3
-
4
- # V=0 quiet, V=1 verbose. other values don't work.
5
- V = 0
6
- V0 = $(V:0=)
7
- Q1 = $(V:1=)
8
- Q = $(Q1:0=@)
9
- ECHO1 = $(V:1=@ :)
10
- ECHO = $(ECHO1:0=@ echo)
11
- NULLCMD = :
12
-
13
- #### Start of system configuration section. ####
14
-
15
- srcdir = .
16
- topdir = /Users/alev/.rvm/rubies/ruby-3.4.4/include/ruby-3.4.0
17
- hdrdir = $(topdir)
18
- arch_hdrdir = /Users/alev/.rvm/rubies/ruby-3.4.4/include/ruby-3.4.0/arm64-darwin24
19
- PATH_SEPARATOR = :
20
- VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
21
- prefix = $(DESTDIR)/Users/alev/.rvm/rubies/ruby-3.4.4
22
- rubysitearchprefix = $(rubylibprefix)/$(sitearch)
23
- rubyarchprefix = $(rubylibprefix)/$(arch)
24
- rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
25
- exec_prefix = $(prefix)
26
- vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
27
- sitearchhdrdir = $(sitehdrdir)/$(sitearch)
28
- rubyarchhdrdir = $(rubyhdrdir)/$(arch)
29
- vendorhdrdir = $(rubyhdrdir)/vendor_ruby
30
- sitehdrdir = $(rubyhdrdir)/site_ruby
31
- rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
32
- vendorarchdir = $(vendorlibdir)/$(sitearch)
33
- vendorlibdir = $(vendordir)/$(ruby_version)
34
- vendordir = $(rubylibprefix)/vendor_ruby
35
- sitearchdir = $(sitelibdir)/$(sitearch)
36
- sitelibdir = $(sitedir)/$(ruby_version)
37
- sitedir = $(rubylibprefix)/site_ruby
38
- rubyarchdir = $(rubylibdir)/$(arch)
39
- rubylibdir = $(rubylibprefix)/$(ruby_version)
40
- sitearchincludedir = $(includedir)/$(sitearch)
41
- archincludedir = $(includedir)/$(arch)
42
- sitearchlibdir = $(libdir)/$(sitearch)
43
- archlibdir = $(libdir)/$(arch)
44
- ridir = $(datarootdir)/$(RI_BASE_NAME)
45
- modular_gc_dir = $(DESTDIR)
46
- mandir = $(datarootdir)/man
47
- localedir = $(datarootdir)/locale
48
- libdir = $(exec_prefix)/lib
49
- psdir = $(docdir)
50
- pdfdir = $(docdir)
51
- dvidir = $(docdir)
52
- htmldir = $(docdir)
53
- infodir = $(datarootdir)/info
54
- docdir = $(datarootdir)/doc/$(PACKAGE)
55
- oldincludedir = $(DESTDIR)/usr/include
56
- includedir = $(SDKROOT)$(prefix)/include
57
- runstatedir = $(localstatedir)/run
58
- localstatedir = $(prefix)/var
59
- sharedstatedir = $(prefix)/com
60
- sysconfdir = $(prefix)/etc
61
- datadir = $(datarootdir)
62
- datarootdir = $(prefix)/share
63
- libexecdir = $(exec_prefix)/libexec
64
- sbindir = $(exec_prefix)/sbin
65
- bindir = $(exec_prefix)/bin
66
- archdir = $(rubyarchdir)
67
-
68
-
69
- CC_WRAPPER =
70
- CC = gcc
71
- CXX = g++
72
- LIBRUBY = $(LIBRUBY_SO)
73
- LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
74
- LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
75
- LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static -framework CoreFoundation $(MAINLIBS)
76
- empty =
77
- OUTFLAG = -o $(empty)
78
- COUTFLAG = -o $(empty)
79
- CSRCFLAG = $(empty)
80
-
81
- RUBY_EXTCONF_H =
82
- cflags = $(hardenflags) -fdeclspec $(optflags) $(debugflags) $(warnflags)
83
- cxxflags =
84
- optflags = -O3 -fno-fast-math
85
- debugflags = -ggdb3
86
- warnflags = -Wall -Wextra -Wextra-tokens -Wdeprecated-declarations -Wdivision-by-zero -Wdiv-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wold-style-definition -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wmisleading-indentation -Wundef
87
- cppflags =
88
- CCDLFLAGS = -fno-common
89
- CFLAGS = $(CCDLFLAGS) -O3 -I/opt/homebrew/opt/libyaml/include -I/opt/homebrew/opt/libksba/include -I/opt/homebrew/opt/readline/include -I/opt/homebrew/opt/zlib/include -I/opt/homebrew/opt/openssl@1.1/include $(cflags) -fno-common -pipe $(ARCH_FLAG)
90
- INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
91
- DEFS =
92
- CPPFLAGS = -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT $(DEFS) $(cppflags)
93
- CXXFLAGS = $(CCDLFLAGS) -fdeclspec $(ARCH_FLAG)
94
- ldflags = -L. -L/opt/homebrew/opt/libyaml/lib -L/opt/homebrew/opt/libksba/lib -L/opt/homebrew/opt/readline/lib -L/opt/homebrew/opt/zlib/lib -L/opt/homebrew/opt/openssl@1.1/lib -fstack-protector-strong
95
- dldflags = -L/opt/homebrew/opt/libyaml/lib -L/opt/homebrew/opt/libksba/lib -L/opt/homebrew/opt/readline/lib -L/opt/homebrew/opt/zlib/lib -L/opt/homebrew/opt/openssl@1.1/lib -Wl,-undefined,dynamic_lookup
96
- ARCH_FLAG = -arch arm64
97
- DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
98
- LDSHARED = $(CC) -dynamic -bundle
99
- LDSHAREDXX = $(CXX) -dynamic -bundle
100
- POSTLINK = dsymutil $@ 2>/dev/null; { test -z '$(RUBY_CODESIGN)' || codesign -s '$(RUBY_CODESIGN)' $@; }
101
- AR = ar
102
- LD = ld
103
- EXEEXT =
104
-
105
- RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)
106
- RUBY_SO_NAME = ruby.3.4
107
- RUBYW_INSTALL_NAME =
108
- RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
109
- RUBYW_BASE_NAME = rubyw
110
- RUBY_BASE_NAME = ruby
111
-
112
- arch = arm64-darwin24
113
- sitearch = $(arch)
114
- ruby_version = 3.4.0
115
- ruby = $(bindir)/$(RUBY_BASE_NAME)
116
- RUBY = $(ruby)
117
- BUILTRUBY = $(bindir)/$(RUBY_BASE_NAME)
118
- ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h
119
-
120
- RM = rm -f
121
- RM_RF = rm -fr
122
- RMDIRS = rmdir -p
123
- MAKEDIRS = /opt/homebrew/opt/coreutils/bin/gmkdir -p
124
- INSTALL = /opt/homebrew/opt/coreutils/bin/ginstall -c
125
- INSTALL_PROG = $(INSTALL) -m 0755
126
- INSTALL_DATA = $(INSTALL) -m 644
127
- COPY = cp
128
- TOUCH = exit >
129
-
130
- #### End of system configuration section. ####
131
-
132
- preload =
133
- libpath = . $(libdir)
134
- LIBPATH = -L. -L$(libdir)
135
- DEFFILE =
136
-
137
- CLEANFILES = mkmf.log
138
- DISTCLEANFILES =
139
- DISTCLEANDIRS =
140
-
141
- extout =
142
- extout_prefix =
143
- target_prefix = /factorization
144
- LOCAL_LIBS =
145
- LIBS = $(LIBRUBYARG_SHARED) -lpthread
146
- ORIG_SRCS = factorization.c
147
- SRCS = $(ORIG_SRCS)
148
- OBJS = factorization.o
149
- HDRS =
150
- LOCAL_HDRS =
151
- TARGET = factorization
152
- TARGET_NAME = factorization
153
- TARGET_ENTRY = Init_$(TARGET_NAME)
154
- DLLIB = $(TARGET).bundle
155
- EXTSTATIC =
156
- STATIC_LIB =
157
-
158
- TIMESTAMP_DIR = .
159
- BINDIR = $(bindir)
160
- RUBYCOMMONDIR = $(sitedir)$(target_prefix)
161
- RUBYLIBDIR = $(sitelibdir)$(target_prefix)
162
- RUBYARCHDIR = $(sitearchdir)$(target_prefix)
163
- HDRDIR = $(sitehdrdir)$(target_prefix)
164
- ARCHHDRDIR = $(sitearchhdrdir)$(target_prefix)
165
- TARGET_SO_DIR =
166
- TARGET_SO = $(TARGET_SO_DIR)$(DLLIB)
167
- CLEANLIBS = $(TARGET_SO) $(TARGET_SO:=.dSYM)
168
- CLEANOBJS = $(OBJS) *.bak
169
- TARGET_SO_DIR_TIMESTAMP = $(TIMESTAMP_DIR)/.sitearchdir.-.factorization.time
170
-
171
- all: $(DLLIB)
172
- static: $(STATIC_LIB)
173
- .PHONY: all install static install-so install-rb
174
- .PHONY: clean clean-so clean-static clean-rb
175
-
176
- clean-static::
177
- clean-rb-default::
178
- clean-rb::
179
- clean-so::
180
- clean: clean-so clean-static clean-rb-default clean-rb
181
- -$(Q)$(RM_RF) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
182
-
183
- distclean-rb-default::
184
- distclean-rb::
185
- distclean-so::
186
- distclean-static::
187
- distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
188
- -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
189
- -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
190
- -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
191
-
192
- realclean: distclean
193
- install: install-so install-rb
194
-
195
- install-so: $(DLLIB) $(TARGET_SO_DIR_TIMESTAMP)
196
- $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
197
- clean-static::
198
- -$(Q)$(RM) $(STATIC_LIB)
199
- install-rb: pre-install-rb do-install-rb install-rb-default
200
- install-rb-default: pre-install-rb-default do-install-rb-default
201
- pre-install-rb: Makefile
202
- pre-install-rb-default: Makefile
203
- do-install-rb:
204
- do-install-rb-default:
205
- pre-install-rb-default:
206
- @$(NULLCMD)
207
- $(TARGET_SO_DIR_TIMESTAMP):
208
- $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
209
- $(Q) $(TOUCH) $@
210
-
211
- site-install: site-install-so site-install-rb
212
- site-install-so: install-so
213
- site-install-rb: install-rb
214
-
215
- .SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S
216
-
217
- .cc.o:
218
- $(ECHO) compiling $(<)
219
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
220
-
221
- .cc.S:
222
- $(ECHO) translating $(<)
223
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
224
-
225
- .mm.o:
226
- $(ECHO) compiling $(<)
227
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
228
-
229
- .mm.S:
230
- $(ECHO) translating $(<)
231
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
232
-
233
- .cxx.o:
234
- $(ECHO) compiling $(<)
235
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
236
-
237
- .cxx.S:
238
- $(ECHO) translating $(<)
239
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
240
-
241
- .cpp.o:
242
- $(ECHO) compiling $(<)
243
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
244
-
245
- .cpp.S:
246
- $(ECHO) translating $(<)
247
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
248
-
249
- .c.o:
250
- $(ECHO) compiling $(<)
251
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
252
-
253
- .c.S:
254
- $(ECHO) translating $(<)
255
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
256
-
257
- .m.o:
258
- $(ECHO) compiling $(<)
259
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
260
-
261
- .m.S:
262
- $(ECHO) translating $(<)
263
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
264
-
265
- $(TARGET_SO): $(OBJS) Makefile
266
- $(ECHO) linking shared-object factorization/$(DLLIB)
267
- -$(Q)$(RM) $(@)
268
- $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
269
- $(Q) $(POSTLINK)
270
-
271
-
272
-
273
- $(OBJS): $(HDRS) $(ruby_headers)
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MTProto
4
- class Connection
5
- attr_reader :client
6
-
7
- def initialize(api_id: nil, api_hash: nil, host:, port: 443, public_key:, dc_number:, test_mode: false, timeout: 10)
8
- @client = Client.new(
9
- api_id: api_id,
10
- api_hash: api_hash,
11
- host: host,
12
- port: port,
13
- public_key: public_key,
14
- dc_number: dc_number,
15
- test_mode: test_mode,
16
- timeout: timeout
17
- )
18
- @connected = false
19
- end
20
-
21
- def connect!
22
- return if @connected
23
-
24
- @client.connect!
25
- @client.make_auth_key
26
- @connected = true
27
- end
28
-
29
- def disconnect!
30
- @client.disconnect! if @connected
31
- @connected = false
32
- end
33
-
34
- def ping(ping_id = nil)
35
- raise NotConnectedError unless @connected
36
-
37
- ping_id ||= rand(2**63)
38
- body = TL::Message.ping(ping_id)
39
-
40
- response_body = @client.rpc_call(body)
41
- message = TL::Message.new(body: response_body)
42
- pong = message.parse_pong
43
-
44
- raise PingMismatchError unless pong[:ping_id] == ping_id
45
-
46
- true
47
- end
48
-
49
- def get_config
50
- raise NotConnectedError unless @connected
51
-
52
- response = @client.help_get_config
53
-
54
- # Handle gzip compression
55
- constructor = response[0, 4].unpack1('L<')
56
- if constructor == TL::GzipPacked::CONSTRUCTOR
57
- response = TL::GzipPacked.unpack(response)
58
- constructor = response[0, 4].unpack1('L<')
59
- end
60
-
61
- # Handle RPC errors
62
- if constructor == TL::RpcError::CONSTRUCTOR
63
- error = TL::RpcError.deserialize(response)
64
- raise MTProto::RpcError.new(error.error_code, error.error_message)
65
- end
66
-
67
- # Parse and return config
68
- if constructor == TL::Config::CONSTRUCTOR || constructor == TL::Config::CONSTRUCTOR_ALT
69
- TL::Config.deserialize(response)
70
- else
71
- raise UnexpectedConstructorError.new(constructor)
72
- end
73
- end
74
-
75
- def send_code(phone_number, code_settings: {})
76
- raise NotConnectedError unless @connected
77
- raise ArgumentError, 'phone_number is required' if phone_number.nil? || phone_number.empty?
78
-
79
- response = @client.auth_send_code(phone_number, code_settings: code_settings)
80
-
81
- # Handle gzip compression
82
- constructor = response[0, 4].unpack1('L<')
83
- if constructor == TL::GzipPacked::CONSTRUCTOR
84
- response = TL::GzipPacked.unpack(response)
85
- constructor = response[0, 4].unpack1('L<')
86
- end
87
-
88
- # Handle RPC errors
89
- if constructor == TL::RpcError::CONSTRUCTOR
90
- error = TL::RpcError.deserialize(response)
91
- raise MTProto::RpcError.new(error.error_code, error.error_message)
92
- end
93
-
94
- # Parse and return sent code
95
- if constructor == TL::SentCode::CONSTRUCTOR
96
- sent_code = TL::SentCode.deserialize(response)
97
- sent_code.to_h
98
- else
99
- raise UnexpectedConstructorError.new(constructor)
100
- end
101
- end
102
- end
103
- end
@@ -1,252 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'serializer'
4
-
5
- module MTProto
6
- module TL
7
- class Message
8
- CONSTRUCTOR_REQ_PQ_MULTI = 0xbe7e8ef1
9
- CONSTRUCTOR_RES_PQ = 0x05162463
10
- CONSTRUCTOR_REQ_DH_PARAMS = 0xd712e4be
11
- CONSTRUCTOR_SERVER_DH_PARAMS_OK = 0xd0e8075c
12
- CONSTRUCTOR_SET_CLIENT_DH_PARAMS = 0xf5045f1f
13
- CONSTRUCTOR_DH_GEN_OK = 0x3bcbf734
14
- CONSTRUCTOR_DH_GEN_RETRY = 0x46dc1fb9
15
- CONSTRUCTOR_DH_GEN_FAIL = 0xa69dae02
16
- CONSTRUCTOR_PING = 0x7abe77ec
17
- CONSTRUCTOR_PONG = 0x347773c5
18
- CONSTRUCTOR_BAD_MSG_NOTIFICATION = 0xa7eff811
19
- CONSTRUCTOR_MSG_CONTAINER = 0x73f1f8dc
20
-
21
- attr_reader :auth_key_id, :msg_id, :body
22
-
23
- def initialize(auth_key_id: 0, msg_id: nil, body: '')
24
- @auth_key_id = auth_key_id
25
- @msg_id = msg_id || generate_msg_id
26
- @body = body
27
- end
28
-
29
- def serialize
30
- auth_key_id_bytes = [@auth_key_id].pack('Q<')
31
- msg_id_bytes = [@msg_id].pack('Q<')
32
- body_length = [@body.bytesize].pack('L<')
33
-
34
- auth_key_id_bytes + msg_id_bytes + body_length + @body
35
- end
36
-
37
- def self.req_pq_multi(nonce)
38
- raise ArgumentError, 'Nonce must be 16 bytes' unless nonce.bytesize == 16
39
-
40
- constructor = [CONSTRUCTOR_REQ_PQ_MULTI].pack('L<')
41
- body = constructor + nonce
42
-
43
- new(auth_key_id: 0, body: body)
44
- end
45
-
46
- def self.req_DH_params(nonce:, server_nonce:, p:, q:, public_key_fingerprint:, encrypted_data:)
47
- raise ArgumentError, 'Nonce must be 16 bytes' unless nonce.bytesize == 16
48
- raise ArgumentError, 'Server nonce must be 16 bytes' unless server_nonce.bytesize == 16
49
-
50
- p_bytes = Serializer.integer_to_bytes(p)
51
- q_bytes = Serializer.integer_to_bytes(q)
52
-
53
- body = Serializer.serialize_int(CONSTRUCTOR_REQ_DH_PARAMS)
54
- body += nonce
55
- body += server_nonce
56
- body += Serializer.serialize_bytes(p_bytes)
57
- body += Serializer.serialize_bytes(q_bytes)
58
- body += Serializer.serialize_long(public_key_fingerprint)
59
- body += Serializer.serialize_bytes(encrypted_data)
60
-
61
- new(auth_key_id: 0, body: body)
62
- end
63
-
64
- def self.set_client_DH_params(nonce:, server_nonce:, encrypted_data:)
65
- raise ArgumentError, 'Nonce must be 16 bytes' unless nonce.bytesize == 16
66
- raise ArgumentError, 'Server nonce must be 16 bytes' unless server_nonce.bytesize == 16
67
-
68
- body = Serializer.serialize_int(CONSTRUCTOR_SET_CLIENT_DH_PARAMS)
69
- body += nonce
70
- body += server_nonce
71
- body += Serializer.serialize_bytes(encrypted_data)
72
-
73
- new(auth_key_id: 0, body: body)
74
- end
75
-
76
- def self.deserialize(data)
77
- if data.bytesize < 20
78
- raise(ArgumentError,
79
- "Invalid MTProto message: expected at least 20 bytes, got #{data.bytesize} bytes (hex: #{data.unpack1('H*')})",
80
- )
81
- end
82
-
83
- auth_key_id = data[0, 8].unpack1('Q<')
84
- msg_id = data[8, 8].unpack1('Q<')
85
- body_length = data[16, 4].unpack1('L<')
86
- body = data[20, body_length]
87
-
88
- new(auth_key_id: auth_key_id, msg_id: msg_id, body: body)
89
- end
90
-
91
- def parse_res_pq
92
- constructor = @body[0, 4].unpack1('L<')
93
- raise "Unexpected constructor: 0x#{constructor.to_s(16)}" unless constructor == CONSTRUCTOR_RES_PQ
94
-
95
- offset = 4
96
-
97
- nonce = @body[offset, 16]
98
- offset += 16
99
-
100
- server_nonce = @body[offset, 16]
101
- offset += 16
102
-
103
- pq_length_byte = @body[offset].unpack1('C')
104
- offset += 1
105
-
106
- pq_length = if pq_length_byte == 254
107
- @body[offset, 3].unpack1('L<') & 0xffffff
108
- offset += 3
109
- else
110
- pq_length_byte
111
- end
112
-
113
- pq = @body[offset, pq_length]
114
- offset += pq_length
115
- offset += padding_length(pq_length + 1)
116
-
117
- vector_constructor = @body[offset, 4].unpack1('L<')
118
- offset += 4
119
- raise 'Expected vector constructor' unless vector_constructor == 0x1cb5c415
120
-
121
- fingerprints_count = @body[offset, 4].unpack1('L<')
122
- offset += 4
123
-
124
- fingerprints = []
125
- fingerprints_count.times do
126
- fingerprints << @body[offset, 8].unpack1('Q<')
127
- offset += 8
128
- end
129
-
130
- {
131
- nonce: nonce,
132
- server_nonce: server_nonce,
133
- pq: pq,
134
- fingerprints: fingerprints
135
- }
136
- end
137
-
138
- def parse_server_DH_params_ok
139
- constructor = @body[0, 4].unpack1('L<')
140
- raise "Unexpected constructor: 0x#{constructor.to_s(16)}" unless constructor == CONSTRUCTOR_SERVER_DH_PARAMS_OK
141
-
142
- offset = 4
143
-
144
- nonce = @body[offset, 16]
145
- offset += 16
146
-
147
- server_nonce = @body[offset, 16]
148
- offset += 16
149
-
150
- length_byte = @body[offset].ord
151
- offset += 1
152
-
153
- if length_byte == 254
154
- length_bytes = @body[offset, 3].bytes
155
- encrypted_answer_length = length_bytes[0] | (length_bytes[1] << 8) | (length_bytes[2] << 16)
156
- offset += 3
157
- else
158
- encrypted_answer_length = length_byte
159
- end
160
-
161
- encrypted_answer = @body[offset, encrypted_answer_length]
162
-
163
- {
164
- nonce: nonce,
165
- server_nonce: server_nonce,
166
- encrypted_answer: encrypted_answer
167
- }
168
- end
169
-
170
- def parse_dh_gen_response
171
- constructor = @body[0, 4].unpack1('L<')
172
-
173
- offset = 4
174
- nonce = @body[offset, 16]
175
- offset += 16
176
-
177
- server_nonce = @body[offset, 16]
178
- offset += 16
179
-
180
- new_nonce_hash = @body[offset, 16]
181
-
182
- case constructor
183
- when CONSTRUCTOR_DH_GEN_OK
184
- { status: :ok, nonce: nonce, server_nonce: server_nonce, new_nonce_hash: new_nonce_hash }
185
- when CONSTRUCTOR_DH_GEN_RETRY
186
- { status: :retry, nonce: nonce, server_nonce: server_nonce, new_nonce_hash: new_nonce_hash }
187
- when CONSTRUCTOR_DH_GEN_FAIL
188
- { status: :fail, nonce: nonce, server_nonce: server_nonce, new_nonce_hash: new_nonce_hash }
189
- else
190
- raise "Unexpected constructor: 0x#{constructor.to_s(16)}"
191
- end
192
- end
193
-
194
- def self.ping(ping_id)
195
- body = Serializer.serialize_int(CONSTRUCTOR_PING)
196
- body += [ping_id].pack('Q<')
197
-
198
- body
199
- end
200
-
201
- def parse_pong
202
- constructor = @body[0, 4].unpack1('L<')
203
-
204
- if constructor == CONSTRUCTOR_BAD_MSG_NOTIFICATION
205
- bad_msg = TL::BadMsgNotification.deserialize(@body)
206
- raise "Bad message notification: #{bad_msg.error_message} (code: #{bad_msg.error_code}, msg_id: #{bad_msg.bad_msg_id}, seqno: #{bad_msg.bad_msg_seqno})"
207
- end
208
-
209
- if constructor == CONSTRUCTOR_MSG_CONTAINER
210
- container = TL::MsgContainer.deserialize(@body)
211
- pong_message = container.messages.find do |msg|
212
- msg[:body][0, 4].unpack1('L<') == CONSTRUCTOR_PONG
213
- end
214
-
215
- raise 'No pong message found in container' unless pong_message
216
-
217
- offset = 4
218
- msg_id = pong_message[:body][offset, 8].unpack1('Q<')
219
- offset += 8
220
- ping_id = pong_message[:body][offset, 8].unpack1('Q<')
221
-
222
- return { msg_id: msg_id, ping_id: ping_id }
223
- end
224
-
225
- raise "Unexpected constructor: 0x#{constructor.to_s(16)}" unless constructor == CONSTRUCTOR_PONG
226
-
227
- offset = 4
228
- msg_id = @body[offset, 8].unpack1('Q<')
229
- offset += 8
230
- ping_id = @body[offset, 8].unpack1('Q<')
231
-
232
- { msg_id: msg_id, ping_id: ping_id }
233
- end
234
-
235
- private
236
-
237
- def generate_msg_id
238
- time = Time.now.to_f
239
- msg_id = (time * (2**32)).to_i
240
- (msg_id / 4) * 4
241
- end
242
-
243
- def padding_length(length)
244
- (4 - (length % 4)) % 4
245
- end
246
-
247
- def self.padding_length(length)
248
- (4 - (length % 4)) % 4
249
- end
250
- end
251
- end
252
- end